我正在尝试将电报列表排序到列表中。
如果PrimeAddress和SecondaryAddress匹配,则电报属于Slave。
设备存储在Datatable中。
我想检查deivce是否已包含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;
}
数据表的结构:
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 :(得分: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初始化为空列表而不是null
修改强> 使用IEqualityComparer进行值比较。以下使用时间戳仅用于相等。代码随使用情况更新。如果ListOfTelegrams可以包含重复项,则您需要在对distinct的调用中处理此问题,否则您可以将调用保留为Distinct。
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();
}
}