[英]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 我需要帮助
data[headindex-1].LineItems.Add(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.