获取字典中接口的重复条目

问题描述

所以我有一个名为IResource的接口,该接口包含这5个属性为只读,但是由于我将这些属性添加Dictionary<IResource,int>中,因此我需要一种比较两个IResource方法,所以我不字典中没有重复项。有没有办法为每个IResource添加Equals(object obj)? 我已经向Equals添加Wood覆盖,它解决了问题,但是我必须在实现Equals(object obj)的每个类中添加IResource

public class Wood : IResource
{
    public string Package => "Core";

    public string Family => "Wood";

    public string Name => "Wood";

    public bool IsFractal => false;

    public ResourceType Type => ResourceType.Natural;
}

PS:我在字典中使用了Add(IResource key,uint value)方法的替代方法,以检查IResource是否已经存在。

    public new void Add(IResource key,uint value)
    {
        if (base.ContainsKey(key))
            base[key] += value;
        else
            base.Add(key,value);
    }

现在,当我向字典中添加一个IResource接口时,它总是会添加一个新条目。

解决方法

您可以将比较移至基类,并在那里覆盖EqualsGetHashCode。只需将要在比较中使用的所有成员添加到抽象类中,然后将其包括在权益比较中即可。

例如:

public enum ResourceType { Natural }

public interface IResource
{
    public string Name { get; }
    public ResourceType ResourceType { get; }
}

public abstract class Resource
{
    public abstract string Name { get; }
    public abstract ResourceType ResourceType { get; }
    // other properties that you want to use for your resource comparision

    public override bool Equals(object obj)
        => obj is Resource r && Name == r.Name && ResourceType == r.ResourceType;

    public override int GetHashCode() => (Name,ResourceType).GetHashCode();
}

public class Wood : Resource,IResource
{
    public override string Name => "Wood";
    public override ResourceType ResourceType => ResourceType.Natural;
    // ... other properties
}
,

您可以创建实现abstract的{​​{1}}类。使用该类并覆盖IResourceEquals

GetHashCode

然后让您的所有资源实现public abstract class Resource : IResource { //make all your interface properties abstract public abstract string Package { get; } public abstract string Family { get; } public abstract string Name { get; } public abstract bool IsFractal { get; } public abstract ResourceType Type { get; } public override bool Equals(object obj) { if (!(obj is Resource resource)) return false; return ReferenceEquals(this,resource) || Package == resource.Package && Family == resource.Family && Name == resource.Family && IsFractal == resource.IsFractal && Type == resource.Type; } public override int GetHashCode() { return HashCode.Combine(Package,Family,Name,IsFractal,Type); } }

abstract class Resource

这将为您提供预期的行为。

,

虽然有可能创建一个抽象的基类(正如其他人指出的那样),但这确实不是一个好主意。您正在创建一个依赖关系,任何实现IResource的类也必须实现相等性,就像为IResource定义它一样。那可能很好,或者可能很难维护并导致错误。

该框架旨在通过允许您自定义词典进行比较的方式来处理这种情况。它通过使用IEqualityComparer来做到这一点。

以下是您的IResource接口的示例:

public class ResourceComparer : IEqualityComparer<IResource>
{
    public bool Equals([AllowNull] IResource x,[AllowNull] IResource y)
    {
        if (null == x && null == y)
            return true;

        if (null == x || null == y)
            return false;

        return x.Package.Equals(y.Package) &&
            x.Family.Equals(y.Family) &&
            x.Name.Equals(y.Name) &&
            x.IsFractal.Equals(y.IsFractal) &&
            x.Type.Equals(y.Type);
    }

    public int GetHashCode([DisallowNull] IResource obj)
    {
        HashCode hash = new HashCode();
        hash.Add(obj.Package);
        hash.Add(obj.Family);
        hash.Add(obj.Name);
        hash.Add(obj.IsFractal);
        hash.Add(obj.Type);
        return hash.ToHashCode();
    }
}

一旦知道了,就可以使用该比较器创建字典。我用过您的Wood类并创建了另一个名为Metal的类。既不必共享基类,也不必重写Equals和GetHashCode。

    static void Main(string[] _)
    {
        var resourceMap = new Dictionary<IResource,uint>(new ResourceComparer());

        var resources = new IResource[] { new Wood(),new Metal(),new Wood(),new Wood() };

        foreach (var r in resources)
        {
            if (resourceMap.TryGetValue(r,out var count))
                resourceMap[r] = count + 1;
            else
                resourceMap.Add(r,1);
        }

        Console.WriteLine(resourceMap[new Wood()]);
        Console.WriteLine(resourceMap[new Metal()]);
    }

这是简单的POCO风格的金属课:

public class Metal : IResource
{
    public string Package => "Core";

    public string Family => "Metal";

    public string Name => "Metal";

    public bool IsFractal => false;

    public ResourceType Type => ResourceType.ManMade;
}

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...