问题
Assume you have a CSV file with the following structure
LINE1: ID,Description,Value
LINE2: 1,Product1,2
LINE3: ,,3
LINE4: ,,4
LINE5: 2,Product2,2
LINE6: ,,3
LINE7: ,,5
With the corresponding FileHelpers
definition class
[DelimitedRecord(",") ]
[IgnoreFirst(1)]
public class Product
{
public int ID { get; set; }
public string Description { get; set; }
[FieldConverter(ConverterKind.Decimal)]
public decimal Val{ get; set; }
}
How do use FileHelpers, to return objects such that each object is fully populated?
Let me clarify, currently, result of using engine.ReadFile
will only produce objects from Lines 2 and 5 as fully populated, which makes sense since the fields are blank. However, objects from Lines 3 and 4 should also have the same ID
and Description
as Line 1. The Value
field should remain untouched for each line. I am not sure what the correct term for the data is, but it seems to 'partially normalised'.
My current approach to solve this is as follows using the AfterRead
event. I do not have a good grasp of Events, Event Handlers, delegates etc, so I am looking for an alternative way to achieve this using FileHelpers. It also seems very clunky.
// call the csv repo using the ffg lines within a console app
var repo2 = new CSVRepositoryBase<Product>();
repo2.AfterRead +=new AfterReadHandler<object>(repo2_AfterRead);
var products = repo2.Read("some file path");
public static Product PreviousRecord { get; set; }
private static void repo2_AfterRead
(EngineBase engine, FileHelpers.Events.AfterReadEventArgs<object> e)
{
var record = (Product)e.Record;
if (PreviousRecord == null)
{
PreviousRecord = new Product();
PreviousRecord.ID = record.ID;
}
if (String.IsNullOrEmpty(record.ID)) // newline record = blank row
{
record.ID = PreviousRecord.ID;
}
PreviousRecord.ID = record.ID;
}
public class CSVRepositoryBase<T> where T : class
{
// shorten for brevity
public IEnumerable<T> Read(string fileName){/*snip*/ }
#region Events
public event AfterReadHandler<object> AfterRead
{
add { engine.AfterReadRecord += value; }
remove { engine.AfterReadRecord -= value; }
}
#endregion
}
回答1:
You can try using the interfaces for AfterRead instead of events like this.
If I understand right you need to do something like that:
[DelimitedRecord(",") ]
[IgnoreFirst(1)]
public class Product
:INotifyRead
{
public int? ID;
public string Description;
[FieldConverter(ConverterKind.Decimal)]
public decimal? Val;
private static Product Previuous;
public void AfterRead(EngineBase engine, string line)
{
if (!ID.HasValue && Previous != null)
this.ID = Previus.ID;
if (!Val.HasValue && Previous != null)
this.Val= Previus.Val;
Previuous = this;
}
}
Hope this helps
来源:https://stackoverflow.com/questions/3923847/how-to-return-fully-populated-objects-using-filehelpers-for-partially-complete-d