确保泛型参数是具体类型

时间:2016-05-02 13:53:47

标签: c# generics

我有一个泛型方法,它使用泛型参数作为字典的键:

<div className={this.rootClassNames()}></div>

此代码效果很好。但是,当然,如果你这样称呼它:

public void MyMethod<T>(IEnumerable<T> myCollection) where T : IMyInterface
{
    var smthg = MyDictionary[typeof(T)];
    //...
}

MyMethod(myCollectionOfT.Cast<IMyInterface>()); 将是T(不是实现IMyInterface的类),字典将没有密钥(这是正常的)。

出现问题时,我很容易抛出异常:

IMyInterface

但是当你的调用使用接口而不是实现它的类时,是否有一种方法(约束或其他)产生编译时错误?

编辑:

D Stanley 提供了一个解决方案:if (typeof(T) == typeof(IMyInterface)) throw new ArgumentException("The generic parameter should be strongly typed.", "T"); 约束会保证new()不是界面。

2 个答案:

答案 0 :(得分:0)

如果您正在处理引用类型,则可以使用class约束。编辑:实际上,它也匹配“仅”接口。哦,好吧。

这更像是一个设计问题 - 你在功能上非虚拟的方式使用接口(在更广泛的意义上)。怎么办

MyMethod(MyListOfDerivedClass.Cast<MyBaseClass>())

由于您违反了接口和继承的设计,因此必须确保您自己的规则不会被破坏。您不能依赖编译器或通常的OOP设计规则,因为您违反了这些规则。

通过将通用方法设计为接受IEnumerable<IMyInterface>类型的任何参数,您可以说IMyInterface的任何实现都应该有效。同样地,只要它们都正确地实现IMyInterface,枚举中的项目是否具有不同类型并不重要。任何方法都是一样的,无论它是否通用。你正在做的事情类似于拥有一个接受Control的方法,但只有在你实际传递LabelButton时才会有效,并且在其他任何事情上失败,包括类型派生来自LabelButton

答案 1 :(得分:-1)

您可以使用类似此代码的内容

public void MyMethod<T>(IEnumerable<T> myCollection) where T : IMyInterface, class, new()
{
    var smthg = MyDictionary[typeof(T)];
    //...
}

根据MSDN Constraints on Type Parameters 修改 class意味着T必须是引用类型;这也适用于任何类,接口,委托或数组类型。所以如果构造函数是公共的,你可以使用new()来检查T是否为class。