简体   繁体   English

新增清单 <t> 使用反射的属性

[英]Adding list<t> property using reflection

I am reading a file which is like 我正在读取一个类似

HDR … HDR…

LIN … 林…

LIN … 林…

LIN … 林…

HDR … HDR…

LIN … 林…

LIN … 林…

Now LIN corresponds to line items and belong to the HDR line above it. 现在,LIN对应于订单项,并且属于其上方的HDR行。

Also, mapping for the data comes from xml which has already been deserilized. 此外,数据映射来自已经反序列化的xml。 This has the mappings like which property to store the data in Header or LineItems class, how many chars to pick, if it is required or not etc. 这具有映射关系,例如,哪个属性将数据存储在Header或LineItems类中,选择多少个字符,是否需要等。

The header model to store data looks like 用于存储数据的标头模型如下所示

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

I am trying to use a generic function to load data before processing it. 我正在尝试使用通用函数在处理数据之前加载数据。

I need help with 我需要帮助

  • (#1) in the below function: is it correct way to make sure that property LineItems is not null before adding the LineItem to it? (#1)在以下函数中:在将LineItem添加到属性之前,是否要确保属性LineItems不为null是正确的方法?
  • How to do (#2) in below function, using reflection to add lineItem to data[headindex-1].LineItems.Add(lineItem) ? 如何在下面的函数中执行(#2),使用反射将lineItem添加到data[headindex-1].LineItems.Add(lineItem)

Here is the function... 这是功能...

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;
}

This article Adding items to List<T> using reflection shows how to do it but this in on main object. 本文使用反射将项目添加到List <T>中,显示了如何执行此操作,但这在主要对象上。 In my case i need to populate data[index].LineItems.Add(...) 就我而言,我需要填充data[index].LineItems.Add(...)

Does this need to be done via reflection? 是否需要通过反射来完成? You could create a simple interface that all of the Header -like classes implement, eg 您可以创建所有类似于Header的类都实现的简单接口,例如

interface IHaveLineItems
{
    void AddLineItem(object item);
}

This can then be implemented on the various Header classes, eg 然后可以在各种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);
    }
}

Your loop could then become: 您的循环可能会变成:

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;
}

If you want to do this via reflection, it's relatively easy. 如果您想通过反射来做到这一点,则相对容易。

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);

This takes advantage of the fact that List<T> implements the IList interface. 这利用了List<T>实现IList接口的事实。 When you call IList.Add() , the value is cast to the correct type and then passed to List<T>.Add() . 当您调用IList.Add() ,该值将IList.Add()转换为正确的类型,然后传递给List<T>.Add()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM