C# C“带”的泛型类;“专业化”;建造师

C# C“带”的泛型类;“专业化”;建造师,c#,generics,C#,Generics,我的课程如下: public class DropDownControl<T, Key, Value> : BaseControl where Key: IComparable { private IEnumerable<T> mEnumerator; private Func<T, Key> mGetKey; private Func<T, Value> mGetValue; private Func<

我的课程如下:

public class DropDownControl<T, Key, Value> : BaseControl
    where Key: IComparable
{
    private IEnumerable<T> mEnumerator;
    private Func<T, Key> mGetKey;
    private Func<T, Value> mGetValue;
    private Func<Key, bool> mIsKeyInCollection;

    public DropDownControl(string name, IEnumerable<T> enumerator, Func<T, Key> getKey, Func<T, Value> getValue, Func<Key, bool> isKeyInCollection)
        : base(name)
    {
        mEnumerator = enumerator;
        mGetKey = getKey;
        mGetValue = getValue;

        mIsKeyInCollection = isKeyInCollection;
    }
public类DropDownControl:BaseControl
where键:i可比较
{
私有IEnumerable mEnumerator;
私有Func-mGetKey;
私有函数管理值;
私有函数错误输入集合;
公共下拉控件(字符串名称、IEnumerable枚举数、Func getKey、Func getValue、Func isKeyInCollection)
:base(名称)
{
mEnumerator=枚举器;
mGetKey=getKey;
mGetValue=getValue;
mIsKeyInCollection=isKeyInCollection;
}
我还想为字典添加一个方便的函数(因为它们可以自己高效地支持所有操作)

但问题是这样的构造函数只指定Key和Value,而不是直接指定T,但T只是KeyValuePair。有没有办法告诉编译器这个构造函数T是KeyValuePair,比如:

public DropDownControl<KeyValuePair<Key, Value>>(string name, IDictionary<Key, Value> dict) { ... }
公共下拉控件(字符串名称,IDictionary dict){…}
目前我使用静态Create函数作为解决方法,但我更喜欢直接构造函数

public static DropDownControl<KeyValuePair<DKey, DValue>, DKey, DValue> Create<DKey, DValue>(string name, IDictionary<DKey, DValue> dictionary)
            where DKey: IComparable
        {
            return new DropDownControl<KeyValuePair<DKey, DValue>, DKey, DValue>(name, dictionary, kvp => kvp.Key, kvp => kvp.Value, key => dictionary.ContainsKey(key));
        }
publicstaticdropdowncontrolcreate(字符串名,IDictionary字典)
其中DKey:i可比较
{
返回新的DropDownControl(name,dictionary,kvp=>kvp.Key,kvp=>kvp.Value,Key=>dictionary.ContainsKey(Key));
}

基本上不是。非泛型类中的静态方法(如DropDownControl[No])是最好的方法,因为调用Create()时应该能够使用类型推断-即

C#3.0通过“var”(这里非常受欢迎)和经过改进的泛型类型推理规则在这里提供了帮助。在某些(更一般的)情况下,另一个类似的选项是扩展方法,但是从字典创建非常特定控件的扩展方法感觉不是很自然-我会使用非扩展方法

比如:

public static class DropDownControl
{
    public static DropDownControl<KeyValuePair<TKey,TValue>, TKey, TValue>
            Create<TKey,TValue>(IDictionary<TKey, TValue> value, string name)
    where TKey : IComparable
    {
        return new DropDownControl<KeyValuePair<TKey, TValue>, TKey, TValue>
            (name, value, pair => pair.Key, pair => pair.Value,
            key => value.ContainsKey(key)
        );
    }
}
公共静态类下拉控件
{
公共静态下拉控制
创建(IDictionary值、字符串名称)
其中TKey:i可比较
{
返回新的下拉控件
(名称,值,pair=>pair.Key,pair=>pair.value,
key=>value.ContainsKey(key)
);
}
}
另一个选择是继承,但我不太喜欢它

public class DropDownControl<TKey, TValue> :
    DropDownControl<KeyValuePair<TKey, TValue>, TKey, TValue>
    where TKey : IComparable
{
    public DropDownControl(IDictionary<TKey, TValue> lookup, string name)
        : base(name, lookup, pair => pair.Key, pair => pair.Value,
            key => lookup.ContainsKey(key)) { }
}
公共类下拉控件:
下拉控制
其中TKey:i可比较
{
公共下拉控件(IDictionary查找,字符串名称)
:base(name,lookup,pair=>pair.Key,pair=>pair.Value,
key=>lookup.ContainsKey(key)){
}
这增加了复杂性并降低了灵活性…我不会这么做


总的来说,听起来您只想使用IDictionary—我想知道您是否可以简化您的控件以仅使用它,并强制非字典调用者将自己包装在IDictionary facade中?

如果
t
将始终是
KeyValuePair
则根本不需要它作为泛型类型参数。只有我们e您使用的每个位置的实际类型
T

否则,如果类型有时必须是其他类型,我建议您可能应该有一个基本类型
DropDownControl:BaseControl
,具有相同类型的受保护字段
Helper
,以及几乎所有方法的虚拟实现,这些方法只需在hat定义了一个派生类
HeldAs
,它用“实”实现覆盖所有方法

DropDownControl
的构造函数将构造
DropDownControl.HeldAs
的一个新实例,并在
Helper
中存储对该实例的引用。然后外部代码可以保存类型为
DropDownControl
的引用并使用它们,而不必知道或关心如何保存键和值。需要创建以不同方式存储内容并使用不同方法提取键和值的内容,可以调用
DropDownControl.HeldAs的构造函数,传递可以将
actualStorageType
转换为键或值的函数(视情况而定)


如果
DropDownControl
的任何方法都希望通过
this
,则
DropDownControl.HeldAs
的构造函数应将
Helper
设置为自身,但基类型的构造函数在构造派生类型实例后,应设置派生实例的
Helper
引用ce自身(基类包装器)。将通过
this
的方法应随后通过
Helper
。这将确保当派生类实例纯粹为了包装而构造时,外部世界将永远不会收到对该派生实例的引用,而是一致地看到包装器。

我正在搜索做C++之类的部分模板特化的方法。但是看起来C现在不能做这个(甚至没有技巧)。事实上,泛型不适合模板专业化。
public class DropDownControl<TKey, TValue> :
    DropDownControl<KeyValuePair<TKey, TValue>, TKey, TValue>
    where TKey : IComparable
{
    public DropDownControl(IDictionary<TKey, TValue> lookup, string name)
        : base(name, lookup, pair => pair.Key, pair => pair.Value,
            key => lookup.ContainsKey(key)) { }
}