This question already has answers here:
Can I Create a Dictionary of Generic Types?
(11 answers)
Closed 9 years ago.
Lets say I have Generic class Foo<T>.
What i want to do is create a singleton for each of a variety of T, and then quickly retrieve them by T later on.
in pseudocode
STORE new Foo<int>
STORE new Foo<MyClass>
GET instance for MyClass -> returns the Foo<MyClass> created above.
In Java I'd make a dictionary that had Type for the key and Foo<*> for the value.
What is the equivalent magic in C#?
Dictionary<Type, object> Dict = new Dictionary<Type, object>();
void Store<T>(Foo<T> foo)
{
Dict.Add(typeof(T), foo);
}
Foo<T> Retrieve<T>()
{
return Dict[typeof(T)] as Foo<T>;
}
There are two ways a method may be given a type: as a Type parameter, or as a generic type parameter. In the former case, if the generic class Foo<T> inherits from a base class (e.g. FooBase) which is not generic in type T, one may use a Dictionary<Type,FooBase>. The FooBase class can include all the members (perhaps as abstract or virtual) of Foo<T> whose signature doesn't depend upon T, so code which is given a Type object for an arbitrary type but does not have a generic type parameter will be able to do with a FooBase anything that could be done without having a generic type parameter. Note that if one has a Type object and wants to use it as though it were a generic type, one will generally have to use Reflection and construct either a delegate or a generic class class instance with the type parameter filled in; once one has done that, one may use the second approach below.
If one has a generic type parameter available (e.g. one is writing a method T GetThing<T>(whatever), one may define a static generic class ThingHolder<T> with a static field T theThing. In that case, for any type TT, ThingHolder<TT>.theThing will be a field of type TT. One will be able to do with this field anything that can be done with a TT.
Related
I want to create a List<System.Type> listOfTypesOfGlasses , where Type must implement a specific interface IGlass , so I could load it with Types of glasses.
Is there a way to enforce in compile time this constraint(must implement IGlass) ?
Implement a method/class that hides the list.
class YourClass {
// intentionally incomplete
private List<Type> listOfTypesOfGlasses;
public void AddToList<T>() : where T: IGlass
{
listOfTypesOfGlasses.Add(typeof(T));
}
}
Edit: below is the original answer here assuming that Type meant a placeholder, not System.Type.
All you should need to do is List<IGlass>.
or
You should write your own wrapper class around List<T> that has the constraint.
or
Subclass List<T> and put the generic constraint on it - however this practice is discouraged.
No - typeof(IGlass) and typeof(Glass) are both Type objects - not different classes that can be filtered in a generic constraint. There's no generic restriction that works off of the values stored. If you want to store instances of types that all implement IGlass that's possible, but you can;t filter the actual Type objects that can be stored.
This question already has answers here:
In C#, What is <T> After a Method Declaration?
(4 answers)
Closed 7 years ago.
What is TProperty in c#?
I saw a code like this:
public abstract class Myclass<T, TProperty> : ....
I know that T is a generic type for the type we are passing. Is TProperty also the same as T.
Anything inside the <> is a generic type indicator. It's name does not make any difference to the compiler, but it should be meaningful for code readability.
Just like in Dictionary<TKey, TValue>.
Of course it has to be unique to it's scope, inclusive of variable names in that scope.
Note that type indicators are not variables, but the Do collide with variable names (Thank you Aravol for your comment on that).
TProperty is a second generic parameter.
Like object parameters on methods, the names have to be unique to distinguish them
Generics can have more than one parameter
According to the C# language spec, any number - see Tuple<T1...T7, TRest> for eaxmple.
By convention, generic parameter names either are or start with a capital "T".
From the description of the class you provide:
public abstract class Myclass<T, TProperty> : ....
It appears the person who created the class intends for an object (T) and an object property (TProperty) to be supplied whenever creating the class.
A best guess would be something like this:
var mine = new Myclass<Generic.List, String>();
It is hard to tell without any more code or the context of how the code is used, though.
i understand what they are, I'm just wondering when is the best time to use them.
My first thought was - when we are building a (static) utility class which should perform certain operations on different data types.
Ergo, it is a good practice to use generic methods to avoid numerous overloads of a certain method? Please comment on this.
I have a small example class. It's just for the sake of an example.
public static class Math<T> where T : operator +, operator -
{
public static T Add(T a1, T a2)
{
return a1+a2;
}
public static T Subtract(T a1, T a2)
{
return a1 - a2;
}
}
Would this be a good usage of generic classes and methods, e.g I wish to add and subtract ints, doubles.. etc.. with the minimum amount of code ?
Why won't this compile? I've tried this as well as modifying the class signature:
public static class Math<T> where T : struct
I understand that I must specify whether the Type parameter is of reference or of value type.
I did that by specifying that T must be constrained as a value type, so why am I still getting error that the operator + and/or - cannot be applied to T (which should specifically be a value type)
No this wouldn't be a good use. Generics are to provide type-safe data structures without knowing the type. Generic constraints allow you to specify some semantics about the type, such as implementing an interface, having a default constructor, or being a class or struct.
Please see these MSDN articles:
An Introduction to C# Generics
Constraints on Type Parameters
.
It won't compile because the operator + parts are not valid constraints.
Being a value type does not infer operators such as + or -, it only infers value-type semantics (inherits object, is a value type, cannot be null, has a default constructor).
Generic Constraints
Generic constraints help the compiler give you more from your T. An unconstrained generic can only be proven to be object, so you only get access to object members on the argument.
If you state: public void Foo<T>() where T : new()
The compiler can prove that your type has a default public parameterless constructor. This is the purpose of constraints, it forces the types that can be party to the generic to conform to a contract.
There are various constraints, but as you have found there are some limitations. Interestingly, there are limitations in C# that do not exist in IL, as explored by Jon Skeet in his Unconstrained Melody library that exposes enum constraints to C#.
As written by others the operator+ isn't a valid constraint. If what you want is to make some generic math, you can use something like:
public static class Add<T>
{
public static readonly Func<T, T, T> Do;
static Add()
{
var par1 = Expression.Parameter(typeof(T));
var par2 = Expression.Parameter(typeof(T));
var add = Expression.Add(par1, par2);
Do = Expression.Lambda<Func<T, T, T>>(add, par1, par2).Compile();
}
}
public static class Math<T>
{
public static T Add(T a1, T a2)
{
return Add<T>.Do(a1, a2);
}
This will create and compile an Expression that does the operation and then cache it in a generic static class.
Sadly with this method you lose the static checking of you compiler (you could do something like:
object res = Math<object>.Add(new object(), new object());
and it would compile correctly. At runtime it would explode.)
In general you can't make a constraint asking for a specific method (static or non-static) or a specific property to be present (operators are like static methods) (with a single exception: the new() constraint that asks for a public parameterless constructor). What you can ask is for an interface to be implemented, or for a base class to be present, or for the generic parameter to be a class or a struct (where the two must be meant as "reference type" and "value type", and not simply as class and struct). Sadly there are no interfaces IAddable, ISubtractable, ... and even if you built them, int, double... wouldn't implement them, and to make it worse, in .NET you can't have generic specializations (a trick of C++ where you define a generic Math<T> and then you define special "cases" explicitly, like Math<int>, Math<double> and so on)
The obvious use case for generic classes is data structures which can then store any type of data without having to treat it all as instances of object. You probably use these all the time - IList<T>, IDictionary<K, V> etc. It lets you store things where you don't know the type when you're writing the structure while retaining type safety. The trick being that you also don't know anything about the type you're storing so you can't do much with it.
Thus generic constraints, which let you say something is a reference type or a value type, or has a parameterless constructor, or implements an interface. These come in useful when you're writing a generic class which has to do something with instances of the parameterised type. Might seem useless - why not just use an interface type as the parameter type and avoid generics altogether? Because generic constraints can force a parameter to conform to more than one interface - something you can't specify in a normal parameter type. Thus you can write a function:
public static void Frobnicate<T>(T thing)
where T : IList<int>, IDisposable
{
// ...
}
You can also stick a single base class name in there too. This is far, far more flexible than specifying concrete types. Sure you could create an interface which inherits from IList<int> and IDisposable but you can't retrofit all disposable lists of integers that might be out there to implement it.
You could also do it at runtime using reflection to inspect things, but this kind of thing is far better handled by the compiler, IMO.
I'm trying to call a method with a definition similar to the following (simplified to avoid confusion):
public static void Register<T>(T value) where T : BaseClass, IInterface
This works fine so long as I have a class instance that defines both of those values. The problem occurs when I pass a `BaseClass' into a method and then try to use that instance in the above declaration. For example:
public class MyClass
{
public MyClass(BaseClass value)
{
Register(value);
}
}
I can pass and instance of a class that implements both BaseClass and IInterface into the constructor, but when I try to use that value in the Register method I get a compilation error stating:
The type 'BaseClass' cannot be used as type parameter 'T' in the generic type or method 'Register(T)'. There is no implicit reference conversion from 'BaseClass' to 'IInterface'.
If I change the type in the constructor like so:
public class MyClass
{
public MyClass(IInterface value)
{
Register(value);
}
}
I get an error stating:
The type 'IInterface' cannot be used as type parameter 'T' in the generic type or method 'Register(T)'. There is no implicit reference conversion from 'IInterface' to 'BaseClass'.
This seems like a bit of a catch-22. Is there a way that I can define the parameter to indicate that it must implement both BaseClass and IInterface?
As I was writing the question I came up with the answer and thought I would post it instead of deleting the question.
I just need to redefine the class:
public class MyClass<T> where T : BaseClass, IInterface
{
public MyClass(T value)
{
Register(value);
}
}
The solution given by Matt is an easy answer for situations where it is not necessary to store the passed-in object in a field or collection. If you need to persist the passed-in object, things get much harder. It's easy for a SomeClass<T> where T meets multiple constraints, to store items of class T and pass them as generics to routines with such constraints, but if a class has a method SomeMethod<TParam>(TParam thing) where TParam:IFoo,BaseBar, it won't have any field of type TParam. It could store thing into a field of type IFoo or BaseBar, but unless BaseBar implements IFoo, or all passed-in instances are going to derive from one particular BaseBar derivative which implements IFoo, there's no way to specify that a field's type will meet both constraints (if every instance does derive from one particular BaseBar derivative which implements IFoo, one could simply use that type as a single constraint, or for that matter not bother with generics at all—just use that as the parameter type).
There are ways of getting around these issues, either using Reflection, an interface pattern I call ISelf<T>, or some tricky nested callback interfaces. In some cases, though, it may be better to provide alternatives to methods that take double-constrained parameters (have the methods take a parameter of one constraint type, cast it to the other type, and accept the lack of compile-time safety).
is there any way to get the following (not compiling) code running? i have not found a solution for this.
public class Factory{
public static T Get<T>(V v)
where T : BaseClass<V> {
T someObject = DIContainer.Resolve<T>();
someObject.Set(v);
}
}
T is a normal generic type parameter, used to define the generic method "Get", but has a type constraint which contains a generic itself.
Now the method should define a parameter of which the type is defined by a generic type parameter defined by the generic type parameter of the method.
BaseClass would define a method Set receiving an argument of the type of its generic type parameter.
Meaning it should be possible to call Factory.Get<A<B>>(someObjectCastableToB);.
It would work by defining the method Get as Get with another constraint on V. But then the call would be Factory.Get<A<B>,B>(....) which is not that nice as the declaration of B is there two times.
Thanks!
Unlike C++ templates, where you can have "template templates" or "partial specialization", C# generic arguments can only go one-deep at the declaration site, and generic constraints can only tell you about lineage and nothing more. If you want to be able to refer to the generic argument of one of your generic arguments, the only way to do that is, as you have in your example, via a generic constraint on inheritance lineage (T : BaseClass<V>), and then V must also be identified in the generic signature. You'd need something like below.
public class Factory{
public static T Get<T, V>(V v)
where T : BaseClass<V> {
T someObject = DIContainer.Resolve<T>();
someObject.Set(v);
}
}
All I've added here is the generic argument V to your method signature. Again, if you had no base class to anchor V to, you wouldn't be able to do much about your situation. For example, if the runtime type of T itself was generic, and not its base class, you'd be stuck, as in the below sample, which would not compile.
public class Factory{
public static T Get<T, V>(V v)
where T : T<V> {
T someObject = DIContainer.Resolve<T>();
someObject.Set(v);
}
}