简体   繁体   English

构建泛型集合类

[英]Building a generic collection class

I am building the following class to manage a dictionary. 我正在构建以下类来管理字典。

    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);
        }              
    }

But I am getting an error "Operator '==' cannot be applied to operands of type 'TValue' and 'TValue'". 但我得到一个错误“运算符'=='不能应用于'TValue'和'TValue'类型的操作数”。

BTW, I am making this custom collection is because my dictionary has unique value, but I can't get key by value from a dictionary. 顺便说一句,我正在制作这个自定义集合是因为​​我的字典具有独特的价值,但我无法从字典中获取关键值。

Any help is appreciated. 任何帮助表示赞赏。 Thank you. 谢谢。

Did you try using the Equals method? 你尝试过使用Equals方法吗?

if (kvp.Value.Equals(value))

I think this restriction is due to the fact that the == operator can't be used with all types. 我认为这种限制是由于==运算符不能用于所有类型。 Take the following for instance: 举个例子:

struct Test
{
    public int Value;
}

Given the above struct, the following code will not compile: 鉴于上述结构,以下代码将无法编译:

Test a, b;
a = b = new Test();
bool areEqual = a == b; // Operator '==' cannot be applied to 
                        // operands of type 'Test' and 'Test'

However, all types have the Equals method, so calling that will work: 但是,所有类型都有Equals方法,因此调用它将起作用:

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

Fredrik is right ; 弗雷德里克是对的 ; you need to use Equals as you can't presume to be able to use == for all types, since the operator isn't defined for every type. 你需要使用Equals因为你不能假设能够为所有类型使用== ,因为没有为每种类型定义运算符。

Depending on your scenario, it might also make sense to add 根据您的情况,添加也可能有意义

where TValue : IEquatable<TValue>

as a generic type constraint on your class. 作为类的泛型类型约束。 The reason for this is that object.Equals accepts another object as a parameter, which means that if TValue is a value type it will be boxed. 原因是object.Equals接受另一个object作为参数,这意味着如果TValue是一个值类型,它将被装箱。 If it can be known to implement IEquatable<TValue> , on the other hand, then Equals can be resolved to IEquatable<TValue>.Equals *, which takes a TValue as a parameter and therefore won't require value types to be boxed. 另一方面,如果可以知道实现IEquatable<TValue> ,则可以将Equals解析为IEquatable<TValue>.Equals *,它将TValue作为参数,因此不需要装箱值类型。

I might also recommend that you rethink the internal structure of this class. 我可能建议您重新考虑这个类的内部结构。 As it currently stands, there's no reason you need this class at all, as you could easily add an extension method to IDictionary<TKey, TValue> to find a key by value via enumeration over the values. 按照目前的情况,你根本不需要这个类,因为你可以轻松地向IDictionary<TKey, TValue>添加一个扩展方法,通过对值的枚举来按值找到一个键。 What I would do instead is store two dictionaries: a Dictionary<TKey, TValue> and a Dictionary<TValue, TKey> , so that two-way lookup is possible in O(1). 我要做的是存储两个词典: Dictionary<TKey, TValue>Dictionary<TValue, TKey> ,以便在O(1)中进行双向查找。

*By the way, in case you're curious, the reason you can't use IEquatable<T> (or any interface for that matter) to ensure that a type has implemented the == operator is that operators are static , and interfaces cannot provide static methods (and thus can't provide operators). *顺便说一句,如果你很好奇,你不能使用IEquatable<T> (或任何接口)确保类型已经实现了==运算符的原因是运算符是静态的 ,接口不能提供静态方法(因此不能提供运营商)。

When you use generic comparsions I think you should implement a (x)CompareTo(Y) or a comparable class. 当你使用泛型比较时,我认为你应该实现一个(x)CompareTo(Y)或类似的类。 Please correct me if im wrong. 如果我错了请纠正我。

Use the "where" condition on your generic types 在泛型类型上使用“where”条件

class Dictionary<TKey,TVal>
    where TKey: IComparable, IEnumerable
    where TVal: MyI
{
    public void Add(TKey key, TVal val)
    {
    }
}

from http://msdn.microsoft.com/en-us/library/6b0scde8%28VS.80%29.aspx 来自http://msdn.microsoft.com/en-us/library/6b0scde8%28VS.80%29.aspx

你可以使用if(kvp.Value.Equals(value))而不是==。

Don't create a new class. 不要创建新类。 Create a extension method: 创建扩展方法:

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");
    }
}

If you want this to be general purpose, then you will want the definition of equality to be configurable, just as it is in the dictionary for keys. 如果您希望这是通用的,那么您将希望可以配置相等的定义,就像它在键的字典中一样。

Have a property of type IEqualityComparer<TValue> , which is set in the constructor. 有一个IEqualityComparer<TValue>类型的属性,它在构造函数中设置。

Then have a version of the constructor that makes the default EqualityComparer<TValue>.Default . 然后有一个构造函数的版本,它使默认的EqualityComparer<TValue>.Default This will work by calling Equals on the type in question. 这将通过在相关类型上调用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);
    }              
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM