2011-09-01 62 views
0

我想将一个列表的电报排序到一个从站列表。列表排序和模式匹配

如果PrimeAddress和SecondaryAddress匹配,则报文属于从站。

设备存储在Datatable中。

我想检查设备是否已经包含telegramm。

我第一次尝试看起来是这样的:

public static DataTable mdlform_NewMBUStele(int LoggerID, List<MbusTelegram> mList, DataTable _deviceDataTable) 
    { 
     //TODO Das ist total dirty und gar nicht clean hier... 
     foreach (DataRow dRow in _deviceDataTable.Rows) 
     { 
      if (dRow.ItemArray[3] is Slave) 
      { 
       foreach (MbusTelegram mb in mList) 
       { 
        int primeID = (int)dRow.ItemArray[1]; 
        if (primeID == LoggerID) 
        { 
         Slave slv = (Slave)dRow.ItemArray[3]; 
         foreach (MbusTelegram mbus in mList) 
         { 
          if (slv.PrimeAddress == mbus.Header.PrimeAddress && slv.SecondaryAdd == mbus.FixedDataHeader.SecondaryAddress) 
          { 
           if (slv.ListOfTelegramms == null) 
           { 
            slv.ListOfTelegramms = new List<MbusTelegram>(); 
           } 
           if (!slv.ListOfTelegramms.Contains(mbus)) 
           { 
            slv.ListOfTelegramms.Add(mbus); 
            //TODO Check if the slave already contains the telegramm, if so don't add it.. 
           } 
          } 
         } 
        } 
       } 
      } 
     } 
     return _deviceDataTable; 
    } 

DataTable的结构:

private void IniDataTable() 
    { 
     _deviceDataTable = new DataTable("Table"); 
     _deviceDataTable.Columns.Add("ID", typeof(int)); 
     _deviceDataTable.Columns.Add("IDParent", typeof(int)); 
     _deviceDataTable.Columns.Add("Name", typeof(string)); 
     _deviceDataTable.Columns.Add("Object", typeof(object)); 
     _deviceDataTable.Rows.Add(new object[] { 0, DBNull.Value, "Addressen", null }); 
     //GenerateDummyDataTable(); 
     IniDeviceTreeView(); 
    } 

此代码不能很好地工作,并没有检查设备已经包含telegramm。任何更好的想法?

+0

你应该提供的表结构中的问题 – Magnus

+0

好的,请稍等...... – Kingpin

+0

几点意见只是阅读:1)不要使用那些讨厌的索引中的列(3 =对象,等等) - 甚至像“对象”这样的魔法字符串都比这更好。 2.)考虑使用键入的表格 - 比你不需要的 - 做你的问题:没有看到这个东西是什么关于我肯定没有更好的主意...... – Carsten

回答

2

您可以通过几件事来优化代码。首先将所有不会改变的内容从内部循环中取出。例如。每个类型使用ItemArray。它们并不是为内循环的每次迭代而改变,但是对于外循环的每次迭代,其次你似乎在相同的集合上迭代两次,从不使用外循环(mb)的变量,因此你可以完全地重新展开该循环。我已经完成了下面的代码。我也将最内层的循环转换为LINQ,但这主要是因为我发现它更易于阅读。我不确定Distinct是否解决了TODO问题。我不确定我会得到TODO。这可能和它可能不是解决它,你就需要验证

public static DataTable mdlform_NewMBUStele(int LoggerID, List<MbusTelegram> mList, DataTable _deviceDataTable){ 
      //TODO Das ist total dirty und gar nicht clean hier... 
      foreach (DataRow dRow in _deviceDataTable.Rows.Cast<DataRow>().Where(d=>d.ItemArray[3] is Slave)){ 
        var primeID = (int) dRow.ItemArray[1]; 
        var slv = (Slave) dRow.ItemArray[3]; 
        if (slv.ListOfTelegramms == null){ 
         slv.ListOfTelegramms = new List<MbusTelegram>(); 
        } 
        var list = slv.ListOfTelegramms; 
        if (primeID == LoggerID){ 
         var items = from m in mList 
            where 
             slv.PrimeAddress == m.Header.PrimeAddress && 
             slv.SecondaryAdd == m.FixedDataHeader.SecondaryAddress && !list.Contains(m, MbusTelegramEqualityComparer.Default) 
            select m; 
         list.AddRange(items.Distinct(MbusTelegramEqualityComparer.Default)); 
         } 
        } 
      return _deviceDataTable; 
     } 

,如果你也想LINQify它的可读性,你可以做如下(这可能会执行略差):

public static DataTable mdlform_NewMBUStele2(int LoggerID, List<MbusTelegram> mList, DataTable _deviceDataTable){ 
      var pairs = from dRow in _deviceDataTable.Rows.Cast<DataRow>() 
         where dRow.ItemArray[3] is Slave 
         let primeID = (int) dRow.ItemArray[1] 
         let slv = (Slave) dRow.ItemArray[3] 
         let list = slv.ListOfTelegramms 
         where primeID == LoggerID 
         select 
          new{ 
            list, 
            items = (from m in mList 
              where 
               slv.PrimeAddress == m.Header.PrimeAddress && 
               slv.SecondaryAdd == m.FixedDataHeader.SecondaryAddress && 
               !list.Contains(m, MbusTelegramEqualityComparer.Default) 
              select m).Distinct(MbusTelegramEqualityComparer.Default) 
           }; 
      foreach (var pair in pairs){ 
       pair.list.AddRange(pair.items); 
      } 
      return _deviceDataTable; 
     } 

后者为例要求ListOfTelegrams被初始化为空列表,而不是空

EDIT 具有值比较使用的IEqualityComparer。下面仅使用时间戳进行平等。代码随使用情况而更新。如果ListOfTelegrams可以包含重复项,则需要在呼叫中处理此项以区分不同情况,否则可以将呼叫留给Distinct out。

public class MbusTelegramEqualityComparer : IEqualityComparer<MbusTelegram>{ 
     public static readonly MbusTelegramEqualityComparer Default = new MbusTelegramEqualityComparer(); 
     public bool Equals(MbusTelegram x, MbusTelegram y){ 
      return x.TimeStamp == y.TimeStamp; 
     } 

     public int GetHashCode(MbusTelegram obj){ 
      return obj.TimeStamp.GetHashCode(); 
     } 
    } 
+0

你的代码工作正常,但它不能修复双重的if我运行两次函数。任何想法如何解决这个问题?也许。包含? – Kingpin

+0

取决于你在谈论重复时的含义。它不会(至少不应该)添加相同的对象两次,但可能会添加两个具有相同值的对象。如果你让我知道它是参考平等还是价值平等。如果是后者,则需要实施一些比较,但我可以展示如何使用它 –

+0

它是价值平等,这就是为什么conatins不起作用的问题。每个MbusTelegram都有时间戳。所以我必须检查设备列表中是否存在具有相同时间戳的telegramm。我不会放弃谁来实现这一点,也许在第一个地方删除所有这些? – Kingpin