代码之家  ›  专栏  ›  技术社区  ›  Ahmad

如何使用FileHelpers为部分完整的数据返回完全填充的对象?

  •  0
  • Ahmad  · 技术社区  · 15 年前

    假设您有一个CSV文件,其结构如下

     LINE1:  ID,Description,Value
     LINE2:  1,Product1,2
     LINE3:  ,,3
     LINE4:  ,,4
     LINE5:  2,Product2,2
     LINE6:  ,,3
     LINE7:  ,,5 
    

    与相应的 FileHelpers 定义类

    [DelimitedRecord(",") ]
    [IgnoreFirst(1)] 
    public class Product
    {
        public int ID { get; set; }
        public string Description { get; set; }
    
        [FieldConverter(ConverterKind.Decimal)]
        public decimal Val{ get; set; }
    }
    

    如何使用 FileHelpers ,返回对象以使每个对象都已完全填充?

    engine.ReadFile 将只生成第2行和第5行中完全填充的对象,这是有意义的,因为字段是空的。但是,第3行和第4行中的对象也应该具有相同的 ID 和 Description Value 对于每一行,字段应该保持不变。我不确定数据的正确术语是什么,但它似乎“部分正常化”。

    AfterRead 事件。我对事件、事件处理程序、委托等没有很好的理解,因此我正在寻找使用filehelper实现这一点的另一种方法。它看起来也很笨重。

        // 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 回复  |  直到 15 年前
        1
  •  2
  •   Marcos Meli    15 年前

    您可以尝试将接口用于AfterRead,而不是像这样的事件。

    如果我理解正确,你需要这样做:

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

    希望这有帮助