2016-04-28 190 views
2

你好,我有一个方法比较2个列表的差异对象。现在这个工作,但一次只有一个属性。怎样才能获得一个列表?

这里是方法:

public SPpowerPlantList compareTwoLists(string sqlServer, string database, DateTime timestampCurrent, string noteCurrent, DateTime timestampOld, string noteOld) 
    { 

     int count = 0; 
     SPpowerPlantList powerPlantListCurrent = loadProjectsAndComponentsFromSqlServer(sqlServer, database, timestampCurrent, noteCurrent); 
     SPpowerPlantList powerPlantListOld = loadProjectsAndComponentsFromSqlServer(sqlServer, database, timestampOld, noteOld); 
     SPpowerPlantList powerPlantListDifferences = new SPpowerPlantList(); 
     count = powerPlantListOld.Count - powerPlantListCurrent.Count; 

     var differentObjects = powerPlantListCurrent.Where(p => !powerPlantListOld.Any(l => p.mwWeb == l.mwWeb)).ToList(); 

     foreach (var differentObject in differentObjects) 
     { 
      powerPlantListDifferences.Add(differentObject); 
     } 

     return powerPlantListDifferences; 

    } 

这工作,我也得到在新的清单4级的对象。问题是我有一些其他属性需要比较。例如名称而不是mwWeb。当我尝试更改它时,我需要为每个新属性添加一个新列表和一个新的Foreach循环。

例如

int count = 0; 
    SPpowerPlantList powerPlantListCurrent = loadProjectsAndComponentsFromSqlServer(sqlServer, database, timestampCurrent, noteCurrent); 
    SPpowerPlantList powerPlantListOld = loadProjectsAndComponentsFromSqlServer(sqlServer, database, timestampOld, noteOld); 
    SPpowerPlantList powerPlantListDifferences = new SPpowerPlantList(); 
    SPpowerPlantList powerPlantListDifferences2 = new SPpowerPlantList(); 

    count = powerPlantListOld.Count - powerPlantListCurrent.Count; 

    var differentObjects = powerPlantListCurrent.Where(p => !powerPlantListOld.Any(l => p.mwWeb == l.mwWeb)).ToList(); 
    var differentObjects2 = powerPlantListCurrent.Where(p => !powerPlantListOld.Any(l => p.shortName == l.shortName)).ToList(); 

    foreach (var differentObject in differentObjects) 
    { 
     powerPlantListDifferences.Add(differentObject); 
    } 

    foreach (var differentObject in differentObjects2) 
    { 
     powerPlantListDifferences2.Add(differentObject); 
    } 

    return powerPlantListDifferences; 

有没有办法来防止这种情况?或者制作更多的查询并且只返回1个包含所有不同对象的列表?

我试过exceptintersect但没有奏效。 因此,任何帮助或建议将是伟大的,thx为您的时间。

PS:如果我的问题风格有问题,请对我说,因为我试图学会提出更好的问题。

+0

我认为你需要实现的IEqualityComparer为对象。然后'除了'和'交叉'将起作用。 https://blogs.msdn.microsoft.com/mcsuksoldev/2011/04/05/linq-distinct-and-iequalitycomparer-implementation/ –

+0

为什么不重写'Equals()'和'GetHashCode()'? – derpirscher

回答

2

您可以简单地连锁,你想用你Where()子句中进行比较的属性或声明:

// This should get you any elements that have different A properties, B properties, etc. 
var different = current.Where(p => !old.Any(l => p.A == l.A || p.B == l.B)) 
         .ToList(); 

如果这不起作用,并且您确实想使用Except()Intersect()方法正确比较对象,你可以写自己的自定义IEqualityComparer<YourPowerPlant>使用正确比较它们:

class PowerPlantComparer : IEqualityComparer<YourPowerPlant> 
{ 
    // Powerplants are are equal if specific properties are equal. 
    public bool Equals(YourPowerPlant x, YourPowerPlant y) 
    { 
     // Check whether the compared objects reference the same data. 
     if (Object.ReferenceEquals(x, y)) return true; 

     //Check whether any of the compared objects is null. 
     if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null)) 
      return false; 

     // Checks the other properties to compare (examples using mwWeb and shortName) 
     return x.mwWeb == y.mwWeb && x.shortName == y.shortName; 
    } 

    // If Equals() returns true for a pair of objects 
    // then GetHashCode() must return the same value for these objects. 

    public int GetHashCode(YourPowerPlant powerPlant) 
    { 
     // Check whether the object is null 
     if (Object.ReferenceEquals(powerPlant, null)) return 0; 

     // Get hash code for the mwWeb field if it is not null. 
     int hashA = powerPlant.mwWeb == null ? 0 : powerPlant.mwWeb.GetHashCode(); 

     // Get hash code for the shortName field if it is not null. 
     int hashB = powerPlant.shortName == null ? 0 : powerPlant.shortName.GetHashCode(); 

     // Calculate the hash code for the product. 
     return hashA^hashB; 
    } 
} 

,然后你可能会使用像下面这样的一个根据您的需要:

var different = current.Except(old,new PowerPlantComparer()); 

或:

var different = current.Intersect(old,new PowerPlantComparer()); 
+0

Thx这与clas很好地工作。 – opelhatza

0

要做到这一点是比较一些独特的标识符,最简单的方法(ID)

var differentObjects = powerPlantListCurrent 
    .Where(p => !powerPlantListOld.Any(l => p.Id == l.Id) 
    .ToList(); 

如果其他属性可能已更新,并要检查过,你就必须比较所有他们检测到现有的元素进行修改:

实现一个camparison法(IComparableIEquatableIEqualityComparer,或覆盖Equals),或者,如果是因为你不是你自己写的类(生成的或外部的代码是不可能的组装),编写一个方法来比较两个o f那些SPpowerPlantList元素并使用它来代替比较Linq中的每个属性。例如:

public bool AreThoseTheSame(SPpowerPlantList a,SPpowerPlantList b) 
{ 
    if(a.mwWeb != b.mwWeb) return false; 
    if(a.shortName != b.shortName) return false; 
    //etc. 
    return true; 
} 

然后用此取代你的区别来电:

var differentObjects = powerPlantListCurrent 
    .Where(p => !powerPlantListOld.Any(l => AreThoseTheSame(p,l)) 
    .ToList(); 
+1

使用IEqualityComparer更简单,更美观。 :-) –

+0

@ Sebastian-Schulz同意,这就是为什么我提到它作为首选选项:),编辑:哦,等等 - 这是我忘记的界面 –

+0

记住,当你重写'Equals'时,你必须重写'GetHashCode'! – derpirscher

1

作为Rion Williams的建议,一种方法是使用IEqualityComparer,如果您想要更灵活的解决方案,可以将逻辑分为两部分。首先创建接受两个列表的帮助器方法,并在其中定义您希望比较的属性。例如:

public static class Helper 
{ 
    public static SPpowerPlantList GetDifference(this SPpowerPlantList current, SPpowerPlantList old, Func<PowerPlant, PowerPlant, bool> func) 
    { 
     var diff = current.Where(p => old.All(l => func(p, l))).ToList(); 
     var result = new SPpowerPlantList(); 

     foreach (var item in diff) result.Add(item); 

     return result; 
    } 
} 

并使用它:

public SPpowerPlantList compareTwoLists(string sqlServer, string database, 
             DateTime timestampCurrent, string noteCurrent, 
                DateTime timestampOld, string noteOld) 
{  
    var powerPlantListCurrent = ...; 
    var powerPlantListOld = ...; 

    var diff = powerPlantListCurrent.GetDifference(
      powerPlantListOld, 
      (x, y) => x.mwWeb != y.mwWeb || 
         x.shortName != y.shortName); 


    return diff; 
} 

附:如果能更好地满足您的需求,您可以在现有类的内部移动方法:

public class MyClass 
{ 
    public SPpowerPlantList GetDifference(SPpowerPlantList current, SPpowerPlantList old, Func<PowerPlant, PowerPlant, bool> func) 
    { 
     ... 
    }   
} 

,并呼吁它(内部类):

var result = GetDifference(currentValues, oldValues, (x, y) => x.mwWeb != y.mwWeb); 
+0

刚刚尝试过,这一个也很好,但我不应该添加一个新的类..... – opelhatza

+0

@ lndanderl没有真正的理由添加类助手 - 这只是为了方便,你可以删除'this'关键字并将其作为正常的静态方法在现有类中移动。 – Fabjan

+0

哦,没有注意到,我再试一次。谢谢 – opelhatza