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
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.