So I have class which accepts a generic type parameter and does a little special handling if the type parameter is a subclass of a given type.
IEnumerable<T> models = ...
// Special handling of MySpecialModel
if (filterString != null && typeof(MySpecialModel).IsAssignableFrom(typeof(T)))
{
var filters = filterString.Split(...);
models =
from m in models.Cast<MySpecialModel>()
where (from t in m.Tags
from f in filters
where t.IndexOf(f, StringComparison.CurrentCultureIgnoreCase) >= 0
select t)
.Any()
select (T)m;
}
But I'm getting an exception on the last line
Cannot convert type 'MySpecialModel' to 'T'
If I change the code to use as instead of casting, I get this error.
The type parameter 'T' cannot be used with the 'as' operator because it does not have a class type constraint nor a 'class' constraint.
What am I missing here?
Update
This class needs can take any type parameter, including structs and built-in types, so a generic constraint would not be a suitable solution in my case.
Do Select(x => (MySpecialModel)x)
The LINQ Cast<T> method will only work for casting elements to that the element already is (such as a base type, derived type, or interface). It is not intended to cast objects that are able to be cast to a target type. (e.g. new List<int>{1,2,3}.Cast<long>() will throw an exception as well.
The above answer wasn't wrong, but it doesn't address the question.
Just because you have proved with reflection that a generic parameter is bound to a given type, doesn't mean that the compiler knows that it is. In order to make this work, you will need to cast your T instance to a common type (e.g. object), then cast it to the specific type. e.g. (changing the last line in your query to select (T)(object)m should do the trick.
Try the following
select (T)(object)m;
At runtime you've verified that T is a subtype of MySpecialModel but the compiler doesn't have access to this information at compile time. It just sees an attempted conversion between 2 unrelated types: T and MySpecialModel.
To work around this you need to use object as a middle man. The compiler understands how to convert MySpecialModel to object and to go from object to T.
The most straightforward fix is to cast to object first before the cast to T:
select (T)(object)m;
The problem is your check occurs at runtime, but the compiler doesn't know that T must be an instance of MySpecialModel within the if statement. Therefore it just sees you are trying to cast to some arbitrary type T from MySpecialModel which is not safe, hence the error.
If you know that the generic type will always be a class, you can add a type constraint on your class:
public class Test<T> where T : class {}
Otherwise perform a double cast via object as smartcaveman has suggested:
.Select(x => (T)(object)x);
To use the as keyword, put the class constraint on your generic parameter:
void MyMethod<T>(T item) where T : class
{
//...
}
You might apply Nullable<T> constraint - that should enable the possibility to cast (at least using "as").
Related
Can somebody explain me the need in C# language for typeof(SomeGenericType<>), with no concrete parameters specified.
I put together the following example:
var t1 = typeof(Nullable<>);
var t2 = typeof(Nullable<int>);
var q = 1 as int?;
var b1 = t1.IsInstanceOfType(q); //false
var b2 = t2.IsInstanceOfType(q); //true
I first thought typeof(Nullable<>) is "more generic" than t2, which specifies generic parameter int, but b1 turns out to be false - so instance of int? is not instance of Nullable<>.
So how a variable should be defined for b1 to be true? what practical uses does it have?
So how a variable should be defined for b1 to be true?
It can't. (In fact, with Nullable<T> you'll run into interesting boxing problems anyway, but there we go...)
At execution time, values are always instances of closed types. Nullable<>, List<> are open generic types. It's never useful to call IsInstanceOfType on such a type. That doesn't mean it's useless though.
Typically open types are used in reflection. For example:
public IList CreateList(Type elementType)
{
Type closedType = typeof(List<>).MakeGenericType(elementType);
return (IList) Activator.CreateInstance(closedType);
}
There can be code high up which is generic, but calls into lower levels passing in Type values instead - the list could then go back up the stack and be cast to IEnumerable<T> for the appropriate value of T.
Likewise you may want to create a closed type with reflection to call a method on it, etc.
You can also use it to find out whether a particular type implements a generic interface for some type argument - for each interface implemented, you can find out if it's generic, get the generic type definition, and see whether that's equal to (say) IEnumerable<>.
That's an open generic type.
It's not an actual type; it is not possible to have an instance of that type.
Instead, you can use it to generate a concrete (closed) generic type, such as Nullable<int>.
You can also check whether a closed generic type is an instance of a particular open generic type by checking its GetGenericTypeDefinition() method.
I have a collection (IQueryable<object>/IEnumerable<object>) and a given Type that I get by reflection at runtime. How can I cast the IQueryable<object> to the specific Type when:
The Type is a class e.g. Person (and I want to make a cast of the IQueryable<object> to IQueryable<Person>)
The Type is a generic collection e.g. IQueryable<Person>
Note that Type is a variable that I get through aVariable.GetType(). I do not know the type beforehand, therefore I cannot use Cast<type> nor (type).
If targeted type is known, go with this
yourIEnumerable.Select(x => (YourType) x);
But as you noted, you don't know the type of the targeted type and you are getting it using object.GetType() so I would recommend to follow this link
For example, if you run the following code...
Type IListType = new List<string>().GetType()
.GetInterface("IList`1")
.GetGenericTypeDefinition();
...and you watch IListType variable, you'll find that the whole Type instance has all properties available like FullName and others.
But what happens when you run the code bellow?
Type IListType2 = typeof(List<>).GetInterface("IList`1")
Now IListType got from a generic type definition isn't the same as the first code sample: most Type properties will return null.
The main issue with this is that IListType == IListType2 doesn't equal while they're the same type.
What's going on?
This is ugly...
Now see what happens if you call IListType2.GetGenericTypeDefinition()... It recovers the type information!
It would be great that a .NET Framework development team member could explain us why an already generic type definition which has strangely lost its metadata has IsGenericTypeDefinition property set to false while it's still a generic type definition, and finally, if you call GetGenericTypeDefinition() on it, you recover the type information.
This is strange...
The following equality will be true:
Type IListType = new List<string>().GetType()
.GetInterface("IList`1")
.GetGenericTypeDefinition();
// Got interface is "like a generic type definition" since it has
// no type for T generic parameter, and once you call
// GetGenericTypeDefinition() again, it recovers the lost metadata
// and the resulting generic type definition equals the one got from
// List<string>!
Type IListType2 = typeof(List<>).GetInterface("IList`1").GetGenericTypeDefinition();
bool y = IListType == IListType2;
The following types are all different and not connected by an inheritance relationship:
IList<T>
IList<int>
IList<string>
All of these have different Type objects because you can do different things with them. The latter two are the specializations of the former. The first is the generic type definition (which you can obtain through GetGenericTypeDefinition).
There is another part to the explanation. When you say class List<T> : IList<T> then the IList<T> part is not equal to typeof(IList<>) because it is already specialized to T. This is no longer a generic type definition. It is a concrete type such as IList<int>. It is specialized to bind its only type argument to the T that List<T> was specialized to.
Experiment for LINQPad:
Type bound = new List<string>().GetType().GetInterface("IList`1");
bound.GenericTypeArguments.Single().Dump(); //string
Type bound = typeof(List<>).GetInterface("IList`1");
bound.GenericTypeArguments.Single().Dump(); //"T"
(bound.GenericTypeArguments.Single() == typeof(List<>).GetGenericArguments().Single()).Dump(); //true
The first version of IList<T> is the actual typed version of IList<T>, let's say IList<string>.
The second one is the generic definition of IList<T> without a type for T.
That makes the two interfaces different. There are not the same, since the first is a concrete version of the second.
Given an object of type System.Reflection.MethodInfo how can I extract generic parameter constraints? Somehow I can not find reasonable information about this.
All you need to do is grab the generic method definition, and list the generic arguments on that:
method
.GetGenericMethodDefinition()
.GetGenericArguments()
.Select(i => i.GetGenericParameterConstraints())
.Dump();
However, note that this doesn't 100% correspond to C#'s generic type constrains - there's a bit of wiggle room. Still, if you only care about e.g. a base-type constraint, it will work fine :)
As an example, class isn't actually a type constraint at all, interestingly, while struct is "translated" as System.ValueType (not too surprising). new() isn't a type constraint either, so this method doesn't work to find that.
If you need to take those constraints into account as well, use the GenericParameterAttributes property in the Select. For example, struct constraint will give you NotNullableValueTypeConstraint | DefaultConstructorConstraint.
You are probably looking for Type.GetGenericParameterConstraints Method ()
Returns an array of Type objects that represent the constraints on the
current generic type parameter.
Also Type.GetGenericArguments Method ()
Returns an array of Type objects that represent the type arguments of
a closed generic type or the type parameters of a generic type
definition
Can somebody explain me the need in C# language for typeof(SomeGenericType<>), with no concrete parameters specified.
I put together the following example:
var t1 = typeof(Nullable<>);
var t2 = typeof(Nullable<int>);
var q = 1 as int?;
var b1 = t1.IsInstanceOfType(q); //false
var b2 = t2.IsInstanceOfType(q); //true
I first thought typeof(Nullable<>) is "more generic" than t2, which specifies generic parameter int, but b1 turns out to be false - so instance of int? is not instance of Nullable<>.
So how a variable should be defined for b1 to be true? what practical uses does it have?
So how a variable should be defined for b1 to be true?
It can't. (In fact, with Nullable<T> you'll run into interesting boxing problems anyway, but there we go...)
At execution time, values are always instances of closed types. Nullable<>, List<> are open generic types. It's never useful to call IsInstanceOfType on such a type. That doesn't mean it's useless though.
Typically open types are used in reflection. For example:
public IList CreateList(Type elementType)
{
Type closedType = typeof(List<>).MakeGenericType(elementType);
return (IList) Activator.CreateInstance(closedType);
}
There can be code high up which is generic, but calls into lower levels passing in Type values instead - the list could then go back up the stack and be cast to IEnumerable<T> for the appropriate value of T.
Likewise you may want to create a closed type with reflection to call a method on it, etc.
You can also use it to find out whether a particular type implements a generic interface for some type argument - for each interface implemented, you can find out if it's generic, get the generic type definition, and see whether that's equal to (say) IEnumerable<>.
That's an open generic type.
It's not an actual type; it is not possible to have an instance of that type.
Instead, you can use it to generate a concrete (closed) generic type, such as Nullable<int>.
You can also check whether a closed generic type is an instance of a particular open generic type by checking its GetGenericTypeDefinition() method.