2011-09-01 61 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