简体   繁体   中英

What's the point of having constraints for type parameters in .NET (base class and interface constraints)

I'm working on a small class library at work, and it naturally involves using generics for this task. But there is this thing that I don't really understand with generics: Why would I need to use generic type parameters, and then constrain the the type parameter to a specific base class or interface.

Here's an example to what I mean:

public class MyGenericClass<T> where T : SomeBaseClass
{
    private T data;
}

And here's the implementation without generics

public class MyClass
{
    private SomeBaseClass data;
}

Are these two definitions the same (if yes, then i don't see the advatage of using generics here)?

If not, what do we benefit from using generics here?

As with almost all uses of generics, the benefit comes to the consumer. Constraining the type gives you the same advantages that you get by strongly typing your parameter (or you can do other things like ensure that there's a public parameterless constructor or ensure that it's either a value or reference type) while still retaining the niceties of generics for the consumer of your class or function.

Using generics also, for example, allows you to obtain the actual type that was specified , if that's of any particular value.

This example is a little contrived, but look at this:

public class BaseClass
{
    public void FunctionYouNeed();
}

public class Derived : BaseClass
{
    public void OtherFunction();
}

public class MyGenericClass<T> where T: BaseClass
{
    public MyGenericClass(T wrappedValue)
    {
        WrappedValue = wrappedValue;
    }

    public T WrappedValue { get; set; }

    public void Foo()
    {
        WrappedValue.FunctionYouNeed();
    }
}

...

var MyGenericClass bar = new MyGenericClass<Derived>(new Derived());

bar.Foo();

bar.WrappedValue.OtherFunction();

The difference is that the former defines the new class as a specific type; the latter simply defines a plain class with a field of that type.

It's all about type safety. Using generics you can return a concrete type (T) instead of some base type which defines the API you need in your generic class. Therefore, the caller of your method won't have to cast the result to the concrete type (which is an error-prone operation).

The main difference is in usage. In the first case, the usage can have:

MyGenericClass<SomeDerivedClass> Variable
Variable.data.SomeDerivedProperty = X

And so that when you use that class, you can still access anything from SomeDerivedClass without casting back to it.

The second example will not allow this.

MyClass.data = SomeDerivedClassInstance
MyClass.data.SomeDerivedProperty = X //Compile Error
((SomeDerivedClass)MyClass.data).SomeDerivedProperty = X //Ewwwww

You will have to cast back up to the SomeDerivedClass (which is unsafe) to use something specific to the derived class.

I don't think that there is a huge amount of difference except that the generic version is constraining your Class , whereas the second is just a constraint on a member of the class. If you added more members and methods to your first Class, you would have the same constraint in place.

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