在<T> C# 中查找列表是否具有<T>(无论属性顺序如何<T>)



我有List<Moves> listOfMoves

ListOfMoves.Add(new Moves()
{
int position1= number1,
int position2= number2,
});

现在我想检查ListOfMoves是否包含例如Move(2,3),但也要检查它是否包含Move(3,2)。我尝试了if(ListOfMoves.Contains(new Move(2,3))),但它不能正常工作。

方法List<T>.Contains(T item)在内部使用方法Object.Equals来检查对象是否相等。因此,如果要将方法List<T>.Contains(T item)与类型T一起使用以检查指定的item是否包含在List<T>中,则需要覆盖类型T中的方法Object.Equals

当您覆盖Object.Equals时,您也应该覆盖Object.GetHashCode。这里有一个很好的解释"当Equals方法被重写时,为什么重写GetHashCode很重要?"。

以下是如何在Move类中重写Object.Equals以满足您的需求:

class Move
{
public Move(int p1, int p2)
{
position1 = p1;
position2 = p2;
}
public int position1 { get; }
public int position2 { get; }
public override bool Equals(object obj)
{
if (obj == null)
return false;
if (ReferenceEquals(this, obj))
return true;
Move other = obj as Move;
if (other == null)
return false;
// Here we specify how to compare two Moves. Here we implement your
// requirement that two moves are considered equal regardless of the
// order of the properties.
return (position1 == other.position1 && position2 == other.position2) ||
(position1 == other.position2 && position2 == other.position1);
}
public override int GetHashCode()
{
// When implementing GetHashCode we have to follow the next rules:
// 1. If two objects are equal then their hash codes must be equal too.
// 2. Hash code must not change during the lifetime of the object.
//    Therefore Move must be immutable. (Thanks to  Enigmativity's usefull tip).
return position1 + position2;
}
}

当您覆盖Object.Equals时,您将能够使用条件ListOfMoves.Contains(new Move(2, 3))来检查移动Move(2, 3)Move(3, 2)是否包含在ListOfMoves中。

以下是演示Object.Equals覆盖的完整示例。

为此,您可以使用LINQ的Any函数。如果你想要位置[(2,3(或(3,2(]的两个组合,你需要两次通过两次检查

ListOfMoves.Any(x => 
(x.position1 == 2 && x.position2 == 3) 
|| (x.position1 == 3 && x.position2 == 2) )

Any返回一个bool,因此您可以将这行代码包装在if语句中,或者存储多次使用的结果

潜在改进

如果你要做很多这样的检查(并且你至少使用c版本7(,你可以考虑一些小的重构,并使用内置的元组类型:https://learn.microsoft.com/en-us/dotnet/csharp/tuples

移动将成为

public class Moves
{
public (int position1, int position2) positions { get; set; }
}

任何呼叫都将成为

ListOfMoves.Any(x => x.positions == (2,3) || x.positions == (3,2))

否则,在代码中,您仍然可以访问每个位置的基本值:

ListOfMoves[0].positions.position1

显然,这取决于代码中的其他内容,所以完全取决于您!

显然它不起作用,因为您无法比较实体本身,而必须使用System.Linq与以下属性值进行比较

ListOfMoves.Where(x => x.position1 == 2 && x.position1 == 3)

注意:您发布的代码根本不应该在中编译

你说如果Move(3,2(或(2,3(在List中,我需要得到true

然后使用Any(),使用类似的相同谓词

if(ListOfMoves.Any(x => x.position1 == 2 && x.position1 == 3))
{
// done something here
}

最新更新