I have a problem with understanding how generic constraints work. I think I am missing something important here. I have enclosed my questions in the comments and would be grateful for providing some explanation.
//1st example:
class C <T, U>
where T : class
where U : struct, T
{
}
//Above code compiles well,
//On first sight it looks like U might be reference type and value type
//at the same time. The only reason I can think of, is that T may be an
//interface which struct can implement, Am I correct?
//2nd example
class CC<T, U>
where T : class, new ()
where U : struct, T
{
}
//I added also a reguirement for parameterless constructor
//and, much to my surprise, it still compiles what is
//a bit inexplicable for me.
//What 'U' would meet the requirement to be
//value type, reference type and have a contructor at the same time?
There can be more than one constraint associated with a type parameter. When this is the case, use a comma-separated list of constraints. In this list, the first constraint must be class or struct or the base class.
C# allows you to use constraints to restrict client code to specify certain types while instantiating generic types. It will give a compile-time error if you try to instantiate a generic type using a type that is not allowed by the specified constraints.
Reference type constraint This type of constraint specifies that the type argument should be a reference type. If we try to substitute a non-reference type for the type argument then we will get a compile-time error.
Interface Type Constraint You can constrain the generic type by interface, thereby allowing only classes that implement that interface or classes that inherit from classes that implement the interface as the type parameter.
There's nothing wrong with that. Let's look at the definition of the constraints on the type parameters:
T : class
- The type argument T must be a reference type, including any class, interface, delegate, or array type.U : struct
- The type argument U must be a value type.U : T
- The type argument U must be or derive from the class T.So all you need to do is find a value type that derives from a reference type. At first that might sound impossible, but if you think a bit harder you will remember that all structs derive from the class object
, so this works fine for both your examples:
new C<object, int>();
However if you swap struct
and class
then it won't compile:
// Error - Type parameter 'T' has the 'struct' constraint so 'T'
// cannot be used as a constraint for 'U'
class C<T, U>
where T : struct
where U : class, T
{
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With