I'm looking at the source code for the MvcContrib Grid and see the class declared as:
public class Grid<T> : IGrid<T> where T : class
What does the where T : class bit do?
It is a generic type constraint.
In this case it means that the generic type (T) must be a reference type, that is class, interface, delegate, or array type.
Other constraints are listed here.
You can also constrain the generic type to inherit from a specific type (base class or interface)
Another examples would be
public A<T> where T : AnInterface
where AnInterface is a interface class. It means then, that T must implement this interface.
These constraints are important, so that the compiler knows the operations which are valid for the type. For example you can not call functions of T without telling the compiler what functions the type provides.
From the Docs http://msdn.microsoft.com/en-us/library/d5x73970.aspx
where T : class
The type argument must be a reference type; this applies also to any class, interface, delegate, or array type.
It is a constraint on the type argument which says that T can either be a class or an interface but not an enum or a struct. So T must be a reference type and not a value type.
Best Regards,
Oliver Hanappi
It restricts T to be a reference type, including any class, interface, delegate, or array type.
It's a generic type constraint. It specifies that the type T has to be a reference type, i.e. a class and not a structure.
you can apply restrictions to the kinds of types that client code can use for type arguments when it instantiates your class are called as Constraints on Type Parameters
E.g : where T : class
Here where T is the Type , The type argument must be a reference type; this applies also to any class, interface, delegate, or array type.
Related
public class Base {...}
public class Complex: Base {...}
public class MyOtherClass<T> {...}
and a list of the two type
List<MyOtherClass<Complex>> listOfComplex
List<MyOtherClass<Base>> listOfBase
I want have a list
listOfComplex.Union(listOfBase)
but i cant convert generic of a type to a generic of another type even if Complex derive fro Base
It's possibble to have a list of a base class?
Although Complex derives from Base, there is no such relationship between MyOtherClass<Complex> and MyOtherClass<Base>. That is the reason why you cannot create an Union of the two lists. For the framework both generic types are completely different.
The solution now really depends on what exactly your class does. Check out the topic of covariance and contravariance here in Docs - these are two special cases in which you will be permitted to create conversions between the two generic types if the types either are input or output only.
You could also add custom cast or manually cast the items to the "base" type before doing the "union" operation.
Because that's how Covariance and Contravariance in Generics works, specifically invariance, it means that you can use only the type originally specified; so an invariant generic type parameter is neither covariant nor contravariant.
You can't assign an instance of List<Base> to a variable of type List<Complex> or in the opposite direction. Same applies to custom generic classes. There is no implicit conversion that compiler could use in order to convert types.
Even if you add generic type constraint. A<B> and A<C> are two different types with no conversion between them even if C is inherited from B (because AC is not inherited from AB)
#MartinZikmund has explained why it does not work. The resolution to this kind of problem is to either derive the generic classes from a non-generic base class or to let them implement a common interface.
public class MyOtherClassBase { }
public class MyOtherClass<T> : MyOtherClassBase { }
Then you can specify MyOtherClassBase as generic parameter to Union explicitly. Now, Union will expect inputs of type IEnumerable<MyOtherClassBase>. Lists of type List<MyOtherClass<T>> are assignment compatible to IEnumerable<MyOtherClassBase>.
var result = listOfComplex.Union<MyOtherClassBase>(listOfBase);
Note the out keyword in the declaration
public interface IEnumerable<out T> : System.Collections.IEnumerable
It makes the interface covariant. See also SO question <out T> vs <T> in Generics and especially Reed Copsey's answer.
You should specify in your generic that T is a class base on Type :
public class MyOtherClass<T> where T : Base {...}
T will be accepted only if derive from Base And Union will should work
Here some documentation about Generics, thanks to #Marie:
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters
This is what I'm looking to do:
public class NormalClass
{
[XmlAttribute]
public int Example;
}
[XmlRoot]
public class GenericClass<T> where T : HasXmlElementAttribute
{
[XmlArray]
public List<T> Variables;
}
I thought where T : IXmlSerializable might work, but it did not.
Is this even possible to do? If so, what is the proper way?
Additional Thoughts/Edit
Is there a way to achieve this same goal? Is there a way to only allow classes that can be xml serialized?
Thanks
Attributes are not part of the type system.
You cannot constrain a type parameter based on the presence of an attribute.
Side note: This justification is not quite valid; constructors aren't part of the type system either, yet : new() is a valid constraint.
No, you cannot use generic type constraints to limit the type parameters by what attributes they are decorated with. You can only use generic type constraints to limit type parameters by:
What base the type parameter inherits
What interfaces the type parameter implements
What constructors the type parameter provides
Whether the type parameter is a value type or a reference type
Further Reading:
Constraints on Type Parameters (C# Programming Guide)
I have a generic interface and I want to constrain types that this generic parameter can accept. Here is the interface:
public interface IBaseRequestRepository<T> where T : IRequestPackage,
IRequestDynamicPackage, IRequestHotelOnly, IRequestFlightOnly
{
IList GetByOccupancyAndTravelDate(int occupancyId, int travelBegYear,
int travelBegDate, int travelEndYear,
int travelEndDate);
}
But this gives an error:
Error 1 The type 'IRequestPackage' cannot be used as type parameter 'T' in the generic type or method 'IBaseRequestRepository'. There is no implicit reference conversion from 'IRequestPackage' to 'IRequestFlightOnly'.
Any suggestions?
You need to satisfy all generic constraints and not just one.
Thus you can't substitute IRequestPackage into T because it doesn't derive from all the other interfaces.
You can pass in either an interface type that inherits from all the interfaces you specified as a constraint or a class type that implements all these interfaces.
The error message suggests that IRequestPackage does not inherit from IRequestFlightOnly - does it?
Note that the where clause is an AND relationship, not an OR - so your where clause is that T must implement ALL of
IRequestPackage,
IRequestDynamicPackage
IRequestHotelOnly,
and IRequestFlightOnly
Looks like you want an IRequest interface or RequestBase abstract class ;)
You should use a type that implement all the interfaces specified by the constraint, not just one of them. It's an "AND", not an "OR"...
You should reconsider your type constraints and your program structure. It looks like you are missing a base interface or an abstract base class.
I tried to google this, but all I could find was documents on ordinary class declarations.
public class DataContextWrapper<T> : IDataContextWrapper where T : DataContext, new()
{
}
I see that the class implements IDataContextWrapper, inherits from DataContext and varies with type T depending on how it is instantiated.
I don't know what "where T" or the ", new()" might mean.
It's a generic constraint and restricts what types can be passed into the generic parameter.
In your case it requires that T is indentical to or derived from DataContext and has a default(argumentless) constructor(the new() constraint).
You need generic constraints to actually do something non trivial with a generic type.
The new() constraint allows you to create an instance with new T().
The DataContext constraint allows you to call the methods of DataContext on an instance of T
MSDN wrote:
where T : <base class name>
The type argument must be or derive from the specified base class.
where T : new()
The type argument must have a public parameterless constructor. When used together with other constraints, the new() constraint must be specified last.
Only allow types T that are derived from or implement DataContext, and have a public constructor that takes no arguments.
It's a generic type constraint and specifies constraint on the generic types (for example, only classes, or must implement a specific interface).
In this case, T must be a class that is either DataContext or inherits from it and must have a parameterless public constructor (the new() constraint).
It's a generic type restriction. In this case, T must inherit from DataContext and be a type with a constructor that takes no arguments.
The where keyword is used to constrain your generic type variable, in your case it means that the type T must be a DataContext and must contain a public default constructor.
where T: DataContext reads as: T must be a (or derived from a) DataContext
the ", new()" reads as: must have an parameterless constructor.
It is constraints in the types that can be used as generic. This gives you compiler checks plus the ability to do something meaningful with T.
Ie. new() tells the compiler that T has to have a parameterless constructor. This means that you can instantiate instances of T by writing new T(); and by knowing T is a DataContext as well, you can both make instances of T but also call methods on it.
It's a generics constraint.
MSDN has more information on that.
See Constraints on Type Parameters (C# Programming Guide)
Where is there to place a constraint upon the type of T. The new says that the type T must be instantiable without any parameters. ie T thing = new T();
See more here
Is it possible for a generic interface's type to be based on a specific parent class?
For example:
public interface IGenericFace<T : BaseClass>
{
}
Obviously the above code doesn't work but if it did, what I'm trying to tell the compiler is that T must be a sub-class of BaseClass. Can that be done, are there plans for it, etc.?
I think it would be useful in terms of a specific project, making sure a generic interface/class isn't used with unintended type(s) at compile time. Or also to sort of self-document: show what kind of type is intended.
public interface IGenericFace<T> where T : SomeBaseClass
What your are referring to is called "Generic Constraints". There are numerous constraints that can be put on a generic type.
Some basic examples are as follows:
where T: struct - The type argument must be a value type. Any value type except Nullable - can be specified. See Using Nullable Types (C# Programming Guide) for more information.
where T : class - The type argument must be a reference type; this applies also to any class, interface, delegate, or array type.
where T : new() - The type argument must have a public parameterless constructor. When used together with other constraints, the new() constraint must be specified last.
where T : <base class name> - The type argument must be or derive from the specified base class.
where T : <interface name> - The type argument must be or implement the specified interface. Multiple interface constraints can be specified. The constraining interface can also be generic.
where T : U - The type argument supplied for T must be or derive from the argument supplied for U. This is called a naked type constraint.
These can also be linked together like this:
C#
public class TestClass<T> where T : MyBaseClass, INotifyPropertyChanged, new() { }
public interface IGenericFace<T> where T : SomeBaseClass
VB
Public Class TestClass(Of T As {MyBaseClass, INotifyPropertyChanged, New})
Public Interface IGenericInterface(Of T As SomeBaseClass)
yes.
public interface IGenericFace<T>
where T : BaseClass
{
}