使用反射添加list <t>属性

时间:2019-06-12 03:58:28

标签: c#

我正在读取一个类似

的文件

HDR…

LIN…

LIN…

LIN…

HDR…

LIN…

LIN…

现在LIN对应于订单项,并且属于其上方的HDR行。

此外,数据映射来自已反序列化的xml。它具有映射关系,例如,哪个属性将数据存储在Header或LineItems类中,选择多少个字符,是否需要等。

用于存储数据的标头模型如下

public class Header
{
    public string Id { get; set; }
    public string Description { get; set; }
    public List<Item> LineItems { get; set; }
}

我正在尝试使用通用函数在处理数据之前先加载数据。

我需要帮助

  • 以下功能中的(#1):在将LineItem添加到属性之前,是否要确保属性LineItems不为null是正确的方法?
  • 如何在下面的函数中执行(#2),使用反射将lineItem添加到data[headindex-1].LineItems.Add(lineItem)

这是功能...

public static List<H> ReadFile<H, I>(ConfigTypeUploadXml uploadConfig, string fileNamePath, ref string errMsg) where H : new() where I : new()
{
    // we'll use reflections to add LineItems to data
    var properties = typeof(H).GetProperties();

    // read the file line by line and add to data. 
    var data = new List<H>();
    var headIndex = 0;
    var lineIndex = 1;

    foreach (var line in File.ReadAllLines(fileNamePath))
    {

        // read HDR line
        if (line.StartsWith("HDR"))
        {
            var header = ReadHeaderLine<H>(uploadConfig, line, errMsg);
            data.Add(header);
            headIndex += 1;
        }

        // read LIN line
        if (line.StartsWith("LIN"))
        {
            var lineItem = ReadItemLine<I>(uploadConfig, line, errMsg);

            foreach (var p in properties)
            {
                if (p.Name != "LineItems")
                    continue;

                //1) if items is null then create the object
                object items = p.GetValue(data[headIndex - 1], null);
                if (items == null)
                    p.SetValue(data[headIndex - 1], new List<I>());

                //2) add line item to data[headIndex - 1].LineItems.Add(lineItem)

            }
        }
        lineIndex += 1;
    }
    return data;
}

本文Adding items to List<T> using reflection显示了如何执行此操作,但这仅在主要对象上进行。就我而言,我需要填充data[index].LineItems.Add(...)

2 个答案:

答案 0 :(得分:1)

这是否需要通过反射来完成?您可以创建一个简单的接口,所有类似Header的类都可以实现,例如

interface IHaveLineItems
{
    void AddLineItem(object item);
}

然后可以在各种Header类上实现此功能,例如

public class Header : IHaveLineItems
{
    public string Id { get; set; }
    public string Description { get; set; }
    public List<Item> LineItems { get; set; }

    void IHaveLineItems.AddLineItem(object item)
    {
        LineItems.Add((Item)item);
    }
}

您的循环可能会变成:

var data = new List<H>();
IHaveLineItems lastHeader = null;
var lineIndex = 1;

foreach (string line in File.ReadAllLines(fileNamePath))
{
    // read HDR line
    if (line.StartsWith("HDR"))
    {
        var header = ReadHeaderLine<H>(uploadConfig, line, errMsg);
        data.Add(header);
        lastHeader = header;
    }

    // read LIN line
    if (line.StartsWith("LIN"))
    {
        var lineItem = ReadItemLine<I>(uploadConfig, line, errMsg);
        lastHeader.AddLineItem(lineItem);
    }

    lineIndex += 1;
}

答案 1 :(得分:1)

如果您想通过反射来做到这一点,则相对容易。

using System.Collections;
using System.Reflection;


var lineItem = ...;
var header = data[data.Count - 1];

var lineItemsProperty = header.GetType().GetProperty("LineItems");
var lineItems = lineItemsProperty.GetValue(header) as IList;
lineItems.Add(lineItem);

这利用了List<T>实现IList接口的事实。调用IList.Add()时,该值将强制转换为正确的类型,然后传递给List<T>.Add()