C# 构建泛型集合类

C# 构建泛型集合类,c#,collections,dictionary,generics,C#,Collections,Dictionary,Generics,我正在构建下面的类来管理字典 public class EnumDictionary<TKey, TValue> { private Dictionary<TKey, TValue> _Dict; public EnumDictionary(Dictionary<TKey, TValue> Dict) { this._Dict = Dict; }

我正在构建下面的类来管理字典

    public class EnumDictionary<TKey, TValue>
    {
        private Dictionary<TKey, TValue> _Dict;

        public EnumDictionary(Dictionary<TKey, TValue> Dict)
        {
            this._Dict = Dict;
        }

        public TKey GetValue(TValue value)
        {
            foreach (KeyValuePair<TKey, TValue> kvp in _Dict)
            {
                if (kvp.Value == value)
                    return kvp.Key;
            }

            throw new Exception("Undefined data type: " + value);
        }              
    }
公共类枚举字典
{
私人词典;
公共词典(Dictionary Dict)
{
这个._Dict=Dict;
}
公钥GetValue(TValue值)
{
foreach(输入的键值对kvp)
{
如果(kvp.Value==值)
返回kvp.Key;
}
抛出新异常(“未定义的数据类型:”+值);
}              
}
但是我得到一个错误“运算符'=''不能应用于'TValue'和'TValue'类型的操作数

顺便说一句,我制作这个自定义集合是因为我的字典有唯一的值,但我无法从字典中按值获取键

    public class EnumDictionary<TKey, TValue>
    {
        private Dictionary<TKey, TValue> _Dict;

        public EnumDictionary(Dictionary<TKey, TValue> Dict)
        {
            this._Dict = Dict;
        }

        public TKey GetValue(TValue value)
        {
            foreach (KeyValuePair<TKey, TValue> kvp in _Dict)
            {
                if (kvp.Value == value)
                    return kvp.Key;
            }

            throw new Exception("Undefined data type: " + value);
        }              
    }

感谢您的帮助。谢谢。

您是否尝试过使用
Equals
方法

if (kvp.Value.Equals(value))
我认为这个限制是因为
=
操作符不能用于所有类型。以以下为例:

struct Test
{
    public int Value;
}
给定上述结构,将不会编译以下代码:

Test a, b;
a = b = new Test();
bool areEqual = a == b; // Operator '==' cannot be applied to 
                        // operands of type 'Test' and 'Test'
但是,所有类型都有
Equals
方法,因此调用该方法将起作用:

Test a, b;
a = b = new Test();
bool areEqual = a.Equals(b);

当您使用泛型比较时,我认为您应该实现(x)CompareTo(Y)或类似的类。如果我错了,请更正。

在泛型类型上使用“where”条件

class Dictionary<TKey,TVal>
    where TKey: IComparable, IEnumerable
    where TVal: MyI
{
    public void Add(TKey key, TVal val)
    {
    }
}
类字典
其中TKey:IComparable,IEnumerable
TVal:MyI在哪里
{
公共无效添加(TKey key,TVal val)
{
}
}

中,可以使用if(kvp.Value.Equals(Value))代替==。

;您需要使用
Equals
,因为您不能假定能够对所有类型使用
=
,因为没有为每个类型定义运算符

根据您的场景,添加

where TValue : IEquatable<TValue>
其中TValue:IEquatable
作为类的泛型类型约束。原因是
object.Equals
接受另一个
object
作为参数,这意味着如果
TValue
是一种值类型,它将被装箱。另一方面,如果已知实现了
IEquatable
,那么
Equals
可以解析为
IEquatable.Equals
*,它将
TValue
作为参数,因此不需要对值类型进行装箱

我可能还建议您重新思考这个类的内部结构。就目前的情况而言,完全没有理由需要这个类,因为您可以轻松地向
IDictionary
添加一个扩展方法,通过对值的枚举按值查找键。我要做的是存储两个字典:一个
字典
和一个
字典
,这样就可以在O(1)中进行双向查找


*顺便说一句,如果您感到好奇,您不能使用
IEquatable
(或任何相关接口)来确保类型实现了
=
运算符的原因是运算符是静态的,接口不能提供静态方法(因此不能提供运算符)。

不要创建新的类。创建扩展方法:

public static class DictionaryHelper
{
    public static TKey GetKeyFromValue<TKey, TValue>(this IDictionary<TKey, TValue> instance, TValue value)
    {
        foreach (var kvp in instance)
        {
            if (kvp.Value.Equals(value))
                return kvp.Key;
        }
        return default(TKey);
    }
}

public class Example
{
    public static void Main(string[] argv)
    {
        Dictionary<string, string> test = new Dictionary<string, string> { { "Mykey", "MyValue" }, { "Key1", "Value2" } };
        string key = test.GetKeyFromValue("MyValue");
    }
}
公共静态类字典帮助器
{
公共静态TKey GetKeyFromValue(此IDictionary实例,TValue值)
{
foreach(实例中的var kvp)
{
如果(千伏值等于(值))
返回kvp.Key;
}
返回默认值(TKey);
}
}
公开课范例
{
公共静态void Main(字符串[]argv)
{
字典测试=新字典{{“Mykey”、“MyValue”}、{“Key1”、“Value2”};
字符串key=test.GetKeyFromValue(“MyValue”);
}
}

如果您希望它是通用的,那么您将希望平等的定义是可配置的,就像在键字典中一样

具有类型为
IEqualityComparer
的属性,该属性在构造函数中设置

然后有一个使默认值
等于comparer.default
的构造函数版本。这将通过对相关类型调用
Equals
来实现

public class EnumDictionary<TKey, TValue>
{
    private Dictionary<TKey, TValue> _Dict;
    private readonly IEqualityComparer<TValue> _cmp;

    public EnumDictionary(Dictionary<TKey, TValue> Dict, IEqualityComparer<TValue> cmp)
    {
        this._Dict = Dict;
        _cmp = cmp;
    }
    public EnumDictionary(Dictionary<TKey, TValue> Dict)
        :this(Dict, IEqualityComparer<TValue>.Default){}

    public TKey GetValue(TValue value)
    {
        foreach (KeyValuePair<TKey, TValue> kvp in _Dict)
        {
            if (cmp.Equals(kvp.Value, value))
                return kvp.Key;
        }

        throw new Exception("Undefined data type: " + value);
    }              
}
公共类枚举字典
{
私人词典;
私有只读IEqualityComparer\u cmp;
公共EnumDictionary(Dictionary Dict,IEqualityComparer cmp)
{
这个._Dict=Dict;
_cmp=cmp;
}
公共词典(Dictionary Dict)
:此(Dict,IEqualityComparer.Default){}
公钥GetValue(TValue值)
{
foreach(输入的键值对kvp)
{
如果(cmp.等于(kvp.值,值))
返回kvp.Key;
}
抛出新异常(“未定义的数据类型:”+值);
}              
}

您试过了吗?奇怪的是,除非我添加约束:
where TValue:class
-,否则我无法让它工作<代码>IEquatable也没有编译。@Kobi:无法获取工作内容?听起来你好像误解了我;如果添加
where TValue:class
约束,则可以使
==
工作,因为
=
是为所有引用类型隐式定义的(它将只使用
对象。ReferenceEquals
)。我在回答中建议的是,OP add
where TValue:IEquatable
,这样
Equals
方法就不会阻塞它的参数。是的,我确实试过这个,它对我来说就像预期的一样。明白了吗,还是我遗漏了什么?@Kobi:是的,我看了你的链接,你似乎认为我在说“如果你在TValue:IEquatable中添加
,你可以使用
=
操作符”。。。但我不是这么说的。希望现在更清楚了?或者你认为我应该改写我的答案吗?显然,我误解了你。抱歉,谢谢您的额外解释。只有在需要进行<或>比较时才需要此项。如果这样做,则应该实现IComparable接口和CompareTo()方法。其他