简体   繁体   中英

Adding list<t> property using reflection

I am reading a file which is like

HDR …

LIN …

LIN …

LIN …

HDR …

LIN …

LIN …

Now LIN corresponds to line items and belong to the HDR line above it.

Also, mapping for the data comes from xml which has already been deserilized. 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.

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?
  • How to do (#2) in below function, using reflection to add lineItem to 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. In my case i need to populate 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

interface IHaveLineItems
{
    void AddLineItem(object item);
}

This can then be implemented on the various Header classes, eg

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. When you call IList.Add() , the value is cast to the correct type and then passed to List<T>.Add() .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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