检查对象的 c# 列表是否包含具有相同变量的对象

本文关键字:对象 变量 是否 列表 检查 包含具 | 更新日期: 2023-09-27 18:27:32

我有一个包含三个值的类,

public class hitOBject {
    public string v1;
    public float v2;
    public float v3;
}

我在运行时动态创建这些对象,这些对象存储在它们自己的列表中。

 List<hitOBject> Detected = new List<hitOBject>();

但是,当一个新对象添加到此列表中时,我首先需要检查是否已经有一个包含重复值的列表。例如。。。

如果我有 2 个命中对象

 obj1            obj2 
 v1 = bob        v1 = bob 
 v2 = 1f         v2 = 3f     
 v3 = 2.5f       v3 = 3.5f  

如果我想检查列表中是否已经存在 V1,有没有一种方法可以做到这一点?

我知道如果它是一个重复的对象,我可以做以下代码吗?

if(!Detected.Contains(object))

但是当我正在寻找子值时,这行不通吗?

谁能指出我正确的方向?

检查对象的 c# 列表是否包含具有相同变量的对象

覆盖GetHashCodeEquals 。如果您打算仅与类中的单个字段/属性进行比较,请仅指定该字段,如下所示:

public class hitOBject
{
    public string v1;
    public float v2;
    public float v3;
    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj)) return false;
        if (ReferenceEquals(this, obj)) return true;
        if (obj.GetType() != this.GetType()) return false;
        return ((hitOBject)obj).v1 == this.v1;
    }
    public override int GetHashCode()
    {
        return (v1 != null ? v1.GetHashCode() : 0);
    }
}

然后您可以使用:

List<hitOBject> Detected = new List<hitOBject>();
Detected.Add(new hitOBject {v1 = "bob", v2 = 1f, v3 = 2.5f});
hitOBject secondObject = new hitOBject {v1 = "bob", v2 = 1f, v3 = 2.5f};
if (Detected.Contains(secondObject))
{
    Console.WriteLine("Alread Exists");
}

由于List<T>.Contains使用Equals来比较相等性,因此覆盖Equals方法将根据字段v1的比较返回一个布尔值。

如果要在List中使用唯一值,则最好使用HashSet<T>因为它只允许基于GetHashCodeEquals实现的唯一值。

HashSet<hitOBject> Detected = new HashSet<hitOBject>();
Detected.Add(new hitOBject {v1 = "bob", v2 = 1f, v3 = 2.5f});
hitOBject secondObject = new hitOBject {v1 = "bob", v2 = 1f, v3 = 2.5f};
Detected.Add(secondObject);

在上面的代码中,最后,您的HashSet将只包含一个项目,secondObject不会添加到HashSet中。

如果不想重写GetHashCodeEquals,则可以使用 LINQ 查询来确定列表中是否存在对象,如下所示:

hitOBject secondObject = new hitOBject {v1 = "bob", v2 = 1f, v3 = 2.5f};
if (Detected.Any(r => r.v1 == secondObject.v1))
{
    //Already exists
}

另一种选择是保持类不变并实现类似IEqualityComparer<T>

private sealed class hitObjectV1EqualityComparer : IEqualityComparer<hitOBject>
{
    public bool Equals(hitOBject x, hitOBject y)
    {
        if (ReferenceEquals(x, y)) return true;
        if (ReferenceEquals(x, null)) return false;
        if (ReferenceEquals(y, null)) return false;
        if (x.GetType() != y.GetType()) return false;
        return string.Equals(x.v1, y.v1);
    }
    public int GetHashCode(hitOBject obj)
    {
        return (obj.v1 != null ? obj.v1.GetHashCode() : 0);
    }
}

然后你可以在你的HashSet<T>构造函数中传递它,如下所示:

另请参阅:常规命名约定 C# - MSDN

HashSet<hitOBject> Detected = new HashSet<hitOBject>(new hitObjectV1EqualityComparer());

稍后添加项目

Detected.Add(new hitOBject {v1 = "bob", v2 = 1f, v3 = 2.5f});
hitOBject secondObject = new hitOBject {v1 = "bob", v2 = 1f, v3 = 2.5f};
Detected.Add(secondObject);

您最终会在HashSet中获得单个项目。

您也可以将该比较器与List<T>.Contains一起使用,例如:

List<hitOBject> Detected = new List<hitOBject>();
var MyEqualityComparer = new hitObjectV1EqualityComparer();
Detected.Add(new hitOBject {v1 = "bob", v2 = 1f, v3 = 2.5f});
hitOBject secondObject = new hitOBject {v1 = "bob", v2 = 1f, v3 = 2.5f};
if (Detected.Contains(secondObject, MyEqualityComparer))
{
    //Already Exists
}
else
{
    Detected.Add(secondObject);    
}
if(!Detected.Any(o1 => o1.v1 == o2.v1 && o1.v2 == o2.v2 && o1.v3 == o2v3))

请遵循 C# 约定。变量(已检测(应为 camelCase,类 (hitObject( 应为 PascalCase

如果列表很大(超过 50 个元素(,请考虑按照建议@Servy使用 HashSet

any 函数是 LINQ 并查找任何匹配项;如果不是任何匹配项,则添加到列表中...这就是你需要的吗?

if (!Detected.Any(Function(i) i.V1 = obj2.V1))
    Detected.Add(obj2);

只需添加即可获得 LINQ 支持:

using System.Linq;

HitObject中实现 IEquatable<T> 接口:

public class HitObject : IEquatable<HitObject>
{
    public string V1;
    public float V2;
    public float V3;
    public bool Equals(HitObject other)
    {
        return this.V1 == other.V1;
    }
}

然后你可以这样使用 Contains 方法:

List<HitObject> detected = new List<HitObject>();
detected.Add(new HitObject
{
    V1 = "bob",
    V2 = 1f,
    V3 = 2.5f
});
HitObject something = new HitObject
{
    V1 = "bob",
    V2 = 3f,
    V3 = 3.5f
};
if (!detected.Contains(something))
{
    // this line will not be executed
    detected.Add(something);
}