简体   繁体   中英

Ensure generic parameter is a concrete type

I have a generic method that uses the generic parameter as the key of a dictionary:

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

This code works well. But of course, if you call it like that:

MyMethod(myCollectionOfT.Cast<IMyInterface>());

T will be IMyInterface (not a class that implements IMyInterface ), and the dictionary won't have the key (which is normal).

I can easily have an exception thrown when the problem occurs:

if (typeof(T) == typeof(IMyInterface)) throw new ArgumentException("The generic parameter should be strongly typed.", "T");

But is there a way (constraint or something) to have a compile-time error when your call uses the interface instead of a class that implements it?

Edit:

D Stanley gave a solution: the new() constraint would garantee that T is not an interface.

You can use the class constraint if you're dealing with reference types. EDIT: Actually, that matches "just" interfaces as well. Oh well.

It's really more of a design problem - you're using interfaces (in broader sense) in a functionally non-virtual way. What if I do

MyMethod(MyListOfDerivedClass.Cast<MyBaseClass>())

?

Since you're violating the design of interfaces and inheritance, you must ensure that your own rules aren't broken. You can't rely on the compiler or the usual OOP design rules, since you're violating those.

By designing your generic method to accept any argument of type IEnumerable<IMyInterface> , you're saying that any implementation of IMyInterface should be valid. The same way, it doesn't matter if the items in the enumerable are of different types as long as they all implement IMyInterface properly. It's the same thing with any method, regardless of whether it's generic or not. What you're doing is akin to having a method that accepts Control , but only works when you actually pass Label or Button , and fails for anything else, including types derived from Label or Button .

You can use something like this code

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

according to MSDN Constraints on Type Parameters Edit: class means that T must be a reference type; this applies also to any class, interface, delegate, or array type. so you can use new() to check that T is class if your constructor is public.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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