Isn't a generic IList assignable from a generic List? - c#

bool IsTypeAGenericList(Type listType)
{
typeof(IList<>).IsAssignableFrom(listType.GetGenericTypeDefinition())
}
returns false when given typeof(List<int>).
I assume this is because the two type parameters can be different, correct?

Actually, this works:
public static bool IsGenericList(Type type)
{
if (!type.IsGenericType)
return false;
var genericArguments = type.GetGenericArguments();
if (genericArguments.Length != 1)
return false;
var listType = typeof (IList<>).MakeGenericType(genericArguments);
return listType.IsAssignableFrom(type);
}

This really has to do with open constructed types.
When you say:
class List<T> : IList<T>
You're actually saying: my class is called List, it has one type parameter called T, and it implements the interface that is constructed from IList<> using the same T. So the T in the definition part and the T in the "implements" part both refer to the same type parameter -- you declare it before the colon, then you immediately reference it after the colon.
It gets confusing because IList<>'s type parameter is also called T -- but that is a different type parameter entirely. So let's re-declare our concrete class like this:
class List<U> : IList<U>
This is completely equivalent to the above, only now we can say "U" when we refer to the type parameter of List, and T when we refer to the one from IList. They're different types.
Now it gets easier to see why the generic type definition List<U> (which is what you mean when you say typeof(List<>)) does not implement the generifc type definition IList<T> (which is what you mean when you say typeof(IList<>)), but rather it implements the open generic constructed type IList<U> (that is, IList constructed with List's own type paremeter).
So basically, generic type definitions never inherit or implement other generic type definitions -- they usually implement open constructed types using their own type parameters with other generic type definitions.
Ripper234's answer shows how to handle this particular case using Reflection, so I won't repeat it; I just wanted to clarify the relationship between those types, and I hope it came out at least somewhat intelligible.

I guess the method doesn't really make sense, because an instance is never of the generic type - it's always constructed with a particular type argument.
In other words, you could never have an "open" variable to assign into, nor a reference to an open instance to use as the value for the assignment.
As you say, you don't know whether the type parameters will be the same - so (for instance) you could define:
class BizarreList<T> : IList<int>
It feels like there should be some way of expressing the relationship though...

Here's the extension method from AutoMapper:
public static bool IsCollectionType(this Type type)
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ICollection<>))
{
return true;
}
IEnumerable<Type> genericInterfaces = type.GetInterfaces().Where(t => t.IsGenericType);
IEnumerable<Type> baseDefinitions = genericInterfaces.Select(t => t.GetGenericTypeDefinition());
var isCollectionType = baseDefinitions.Any(t => t == typeof(ICollection<>));
return isCollectionType;
}

Related

How to get the subtype of a generic class in C#

I have a generic method
public async Task Save<T>(T aggregate) where T : AggregateRoot
From this method I call another generic method
var indexRegistrations = IndexRegistrar.GetAll<T>();
Now in this second generic method, I want to get the real type of T, which is a subtype of AggregateRoot:
public static List<IndexRegistration> GetAll<T>() where T : AggregateRoot
{
return _register.FindAll(r => r.aggregateType == typeof(T));
}
However, the typeof(T) always returns AggregateRoot.
How can I get the real type (=subtype of AggregateRoot) of T?
typeof(T) is correct here.
I tested your case, and typeof(T) always returns the "true" class, not just the type requirement.
public class BaseClass { }
public class DerivedClass: BaseClass { }
public class GenericClass<T> where T : BaseClass
{
public string TypeOf = typeof(T).ToString();
}
public class GenericSuperClass<T> where T : BaseClass
{
public GenericClass<T> Sub = new GenericClass<T>();
}
static void Main(string[] args)
{
Console.WriteLine("1 - " + (new GenericClass<BaseClass>()).TypeOf);
Console.WriteLine("2 - " + (new GenericClass<DerivedClass>()).TypeOf);
Console.WriteLine("3 - " + (new GenericSuperClass<BaseClass>()).Sub.TypeOf);
Console.WriteLine("4 - " + (new GenericSuperClass<DerivedClass>()).Sub.TypeOf);
Console.ReadLine();
}
The output:
1 - BaseClass
2 - DerivedClass
3 - BaseClass
4 - DerivedClass
Note that I've simplified the classnames from the values that are actually returned (e.g Sandbox.TestConsole.Program+DerivedClass).
This directly contradicts your claim that you only ever get the base type (AggregateRoot, in your case).
Reflection is an exception to this.
I can think of one exception to this: when your type is only defined at runtime (e.g. generated from a type name (String)).
However, as this StackOverflow answer explains, generics are intended to provide compile time type safety.
It's not impossible to use reflection to instantiate a generic class at runtime. But when you do so, you are inherently preventing the validity of information (e.g. type names) that are decided at compile-time.
MSDN's page on typeof implicitly states that the return value of typeof is the compile-time type.
Combining these two facts, this means that when you use reflection (i.e. deciding the type at runtime), you cannot rely on typeof (as this returns the compile time type).
The linked MSDN page also mentions how to find the runtime type:
To obtain the run-time type of an expression, you can use the .NET Framework method GetType, as in the following example:
int i = 0;
System.Type type = i.GetType();
However, do note that the GetType() method is only available on an instantiated object, not on a generic type parameter. Generic type parameters are not really types, they are much closer to "type placeholders".
You will need either pass the type as a parameter, or an instantiated object (of the appropriate type).
Conclusion:
If you are using types that are known at compile time, then you can simply use typeof(T), as my example has shown.
If you are deciding the type on runtime using reflection, then you cannot rely on the information provided by typeof(T), and will therefore be required to supply the type. Either you supply it as a Type parameter, or you supply it via an instantiated object, whose runtime type can accurately be tested using the GetType() method.
However, if you are already deciding the type on runtime, then you are better off passing the type itself as a parameter. If you're using reflection here, that means that you must at some point have known which type you wanted to use. Therefore, simply pass that known type as a parameter, which you can then use for your subsequent business logic.
I cannot think of a single scenario in which you aren't either (a) using a type that is known at compile time, nor (b) aware (at runtime) of the type you've decided to use.
As #Flater answer stated, typeof is valid is this case, unless when you instanciated these objects you did not know their types.
So this solution will work for types instanciated at run-time. It will also work if you knew the type at compile time, but it is more complicated and adds complexity.
A solution would be to be able to have an instance of your type, in order to call GetType() on that instance, this would give you the lowest inheriting type of the object.
So, to get an instance, either you change your function and ask for an object to be passed along:
public static List<IndexRegistration> GetAll<T>(T instance) where T : AggregateRoot
{
return _register.FindAll(r => r.aggregateType == instance.GetType());
}
Either you create an instance at run-time, and retrieve the type. This require that you mark the generic type as having a parameterless constructor:
public static List<IndexRegistration> GetAll<T>() where T : AggregateRoot, New()
{
T instance = new T();
return _register.FindAll(r => r.aggregateType == instance.GetType());
}
There is a similar answer for your question:
when-and-where-to-use-gettype-or-typeof.
Generally typeof operator checks for a known at compile-time type. So it will always be AggregateRoot in your case.
To match T itself together with all its inheritors use IsAssignableFrom reflection method, instead of type object comparision:
public static List<IndexRegistration> GetAll<T>() where T : AggregateRoot
{
return _register.FindAll(r => typeof(T).IsAssignableFrom(r.aggregateType));
}

Determining if a field is using a generic parameter

I've been baffled by this and can't seem to get my head around it so hopefully someone can point me in the right direction.
I have a class as follows:
public class Foo<T>
{
public List<T> Data;
}
Now I'm writing code to reflect this class and want to work out a way of determining that the field Data has a generic parameter being used.
My initial approach was to continue going down as many levels as I could and once I hit the IsGenericParameter field set to true I would rather than reflect the type name instead place a "Generic Argument" string there, however I can't seem to get this to work the way I want it to.
I've looked around but every solution I've found seems to point to a dead end with this at the moment.
You want IsGenericType, not IsGenericParameter:
bool isGeneric = typeof(Foo<int>).GetField("Data").FieldType.IsGenericType;
If you want to know of the parameter for the List is generic, then you have to look one more level down:
bool isGeneric = typeof(Foo<>).GetField("Data")
.FieldType
.GetGenericArguments()[0] // only generic argument to List<T>
.IsGenericParameter;
what if Data field was a Dictionary with Dictionary<string, T>. How would I determine which type was using a generic parameter?
Call GetGenericArguments on the type and look at each type in the resulting array
public class Foo<T>
{
public Dictionary<string, T> Bar;
}
Type[] types = typeof(Foo<>).GetField("Bar").FieldType.GetGenericArguments();
Console.WriteLine("{0}\n{1}",
types[0].IsGenericParameter, // false, type is string
types[1].IsGenericParameter // true, type is T
);
Basically, IsGenericParameter is used when looking at the generic parameters of a type to see if it is generic or if is has a type sepcified.
Here is how to distinguish generic types that rely on class type parameter from generic types that do not. Consider this example:
class Foo<T> {
public List<T> field1; // You want this field
public List<int> field2; // not this field
}
Start by getting generic type definition, and pulling its type arguments:
var g = typeof(Foo<string>).GetGenericTypeDefinition();
var a = g.GetGenericArguments();
This will give you an array with a single type that represents generic type parameter T. Now you can go through all fields, and search for that type among generic type arguments of field types, like this:
foreach (var f in g.GetFields()) {
var ft = f.FieldType;
if (!ft.IsGenericType) continue;
var da = ft.GetGenericArguments();
if (da.Any(xt => a.Contains(xt))) {
Console.WriteLine("Field {0} uses generic type parameter", f.Name);
} else {
Console.WriteLine("Field {0} does not use generic type parameter", f.Name);
}
}
This code produces the following output:
Field field1 uses generic type parameter
Field field2 does not use generic type parameter

Want some help understanding this method

class SetMap : KeyedCollection<Type, object>
{
public HashSet<T> Use<T>(IEnumerable<T> sourceData)
{
var set = new HashSet<T>(sourceData);
if (Contains(typeof(T)))
{
Remove(typeof(T));
}
Add(set);
return set;
}
public HashSet<T> Get <T>()
{
return (HashSet<T>) this[typeof(T)];
}
protected override Type GetKeyForItem(object item)
{
return item.GetType().GetGenericArguments().Single();
}
}
would anyone clarify this for me pls. return (HashSet) this[typeof(T)]; with example if possible.
thank you
return (HashSet) this[typeof(T)];
Let me split the statement into parts.
(1) this[...] means using the indexer of this. And this basically means "this object".
(2) The indexer accepts a Type. And in this call to the indexer, the argument is typeof(T).
(3) typeof gets a Type object that corresponds to the type in the (). In this case, the generic type parameter T. And the indexer returns an object.
The parameter (Type) and return type (object) of the indexer can be inferred from the base type of the class: KeyedCollection<Type, object>. I think you can understand this.
(4) The value returned by the indexer gets casted into a HashSet<T>. Again, T is the generic type argument.
(5) The value gets returned to the caller by the return statement.
For more information:
Indexers: https://msdn.microsoft.com/en-us/library/6x16t2tx.aspx
Generics: https://msdn.microsoft.com/en-us/library/512aeb7t.aspx
Casting: https://msdn.microsoft.com/en-us/library/ms173105.aspx\
KeyedCollection: https://msdn.microsoft.com/en-us/library/ms132438(v=vs.110).aspx
typeof: https://msdn.microsoft.com/en-us/library/58918ffs.aspx
It is using generics. A modern programming concept that makes it possible to design classes and methods that defer the specification of one or more types until the class or method is declared and instantiated by client code.
In your example it is defining a hashset that can hold any type.
Read the MSDN documentation in the links I've provided and if you have a more specific questions post them here.

Difference between IsGenericType and IsGenericTypeDefinition

What is the difference between Type.IsGenericType and Type.IsGenericTypeDefinition ? Interestingly enough, MSDN's link for IsGenericTypeDefinition is broken.
Update:
IsGenericTypeDefinition MSDN's entry
After playing a bit with trying to retrieve all the DbSets defined in a given DbContext, I was lead to the following, which behavior I am trying to understand: filtering properties via IsGenericType returns the desired results, while with IsGenericTypeDefinition not (does not return any).
It's interesting that from this post I have the impression that the author did get his DbSets using IsGenericTypeDefinition, while I did not.
Follows a sample that illustrates the discussion:
private static void Main(string[] args)
{
A a = new A();
int propertyCount = a.GetType().GetProperties().Where(p => p.PropertyType.IsGenericType).Count();
int propertyCount2 = a.GetType().GetProperties().Where(p => p.PropertyType.IsGenericTypeDefinition).Count();
Console.WriteLine("count1: {0} count2: {1}", propertyCount, propertyCount2);
}
// Output: count1: 1 count2: 0
public class A
{
public string aaa { get; set; }
public List<int> myList { get; set; }
}
IsGenericType tells you that this instance of System.Type represents a generic type with all its type parameters specified. For example, List<int> is a generic type.
IsGenericTypeDefinition, on the other hand, tells you that this instance of System.Type represents a definition from which generic types can be constructed by supplying type arguments for its type parameters. For example, List<> is a generic type definition.
You can get a generic type definition of a generic type by calling GetGenericTypeDefinition:
var listInt = typeof(List<int>);
var typeDef = listInt.GetGenericTypeDefinition(); // gives typeof(List<>)
You can make a generic type from a generic type definition by providing it with type arguments to MakeGenericType:
var listDef = typeof(List<>);
var listStr = listDef.MakeGenericType(typeof(string));
(This answer compares all of the generic-type-related properties of Type in a side-by-side table below, so if you're already familiar with .NET's generics and just want a reference then just scroll down to the table)
First, remember the difference between parameters and arguments, especially w.r.t. generic type parameters and generic type arguments (and also generic method type parameters and generic method type arguments):
A generic type parameter is the declared type "placeholder" in an "open" generic type.
For example, in class Generic<T0,T1> {}, the T0 and T1 symbols are the generic type parameters. Note that when simply given a generic class definition that's unused then there's no type arguments.
A generic type argument is the type-identifier specified for a generic type parameter by a consumer of a generic class.
For example, in Generic<String,Object> gen = new Generic<String,Object> then...
...the generic type argument for generic type parameter T0 is String.
...the generic type argument for generic type parameter T1 is Object.
However, generic type arguments don't need to be concrete types: they can be a generic type parameter from the consumer's context.
For example, in class Generic<TItem> { public Object Foo() { return new List<TItem>(); } }
...then (inside the Foo method) the class Generic<TItem>'s generic type parameter TItem is used as the generic type argument for List<T>'s generic type parameter T.
Yes, if you get confused by all that don't worry because that's normal.
Finally, generic method type parameters and generic method type arguments work the same way as generic type parameters and generic type arguments, respectively, except they're scoped to a single method:
For example, the class NotGenericClass in class NotGenericClass { void GenericMethod<T>() { } } does not have any generic type parameters, but its method GenericMethod<T>() does have a single generic method type parameter - and if GenericMethod is never ever actually called/used/invoked then GenericMethod will not have any generic method type arguments as those only exist at generic instantiation sites (i.e. at the point of generic instantiation).
Given these C# classes...
class NormalClass { }
class Generic<T> { }
class Derived : Generic<String> { }
class HasGenericMethod { public void Foo<T>() {} }
...and these Type instances from GetGenericArguments():
Type[] genericTypeArgs = typeof(Generic<>).GetGenericArguments();
Type genTypeArg = genericTypeArgs.Single();
Type[] genericMethodTypeArgs = typeof(HasGenericMethod).GetMethod( nameof(HasGenericMethod.Foo) ).GetGenericArguments();
Type genMethodArg = genericMethodTypeArgs.Single();
...then their typeof() expressions will have these properties:
Example
typeof(NormalClass)
typeof(Generic<>)
typeof(Generic<String>)
typeof(Derived)
genTypeArg
genMethodArg
typeof(Generic<String>[])
Type properties
Type.IsTypeDefinition
Yes
Yes
No
Yes
No
No
No
Type.IsGenericType
No
Yes
Yes
No
No
No
No5
Type.ContainsGenericParameters
No
Yes
No
No
Yes4
Yes4
No
Type.GenericTypeArguments
Empty
Empty
{ typeof(String) }
Empty
Empty
Empty
Empty
Type.IsConstructedGenericType
No
No
Yes
No
No
No
No
Type.IsGenericTypeDefinition
No
Yes
No
No
No
No
No
Generic parameter properties:
Type.IsGenericParameter
No
No
No
No
Yes
Yes
No
Type.IsGenericMethodParameter
No
No
No
No
No
Yes
No
Type.IsGenericTypeParameter
No
No
No
No
Yes
No
No
Methods:
Type.GetGenericArguments()
Empty
{ typeof(T) }
{ typeof(String) }
Empty
Empty
Empty
{ typeof(String) }
Type.GetGenericParameterConstraints()
Exception1
Exception1
Exception1
Exception1
Empty
Empty
Exception1
Type.GetGenericTypeDefinition()
Exception2
typeof(Generic<>)
typeof(Generic<>)
Exception2
Exception2
Exception2
Exception2
You can generate this table yourself (albiet, transposed) using this LinqPad script.
As a reminder to myself: if you have a Type object from Object.GetType() for an object that may be either a closed generic type (i.e. Object.GetType().IsConstructedGenericType == true), or is a non-generic type derived from that generic type, and you want to find out what, do this:
private static readonly Type _knownGenericType = typeof(Generic<>);
public static Boolean TryGetTypeArgsOfKnownGenericType( Object obj, [NotNullWhen(true)] out Type? actualArgType )
{
Type t = obj.GetType();
while( t != null )
{
if t.IsConstructedGenericType && t.GetGenericTypeDefinition() == _knownGenericType )
{
Type[] tArgs = t.GetGenericArguments();
actualArgType = tArgs.Single();
return true;
}
t = t.BaseType;
}
actualArgType = null;
return false;
}
So this code below will print "Sucess: T := System.String" twice:
if( TryGetTypeArgsOfKnownGenericType( new Derived(), out Type? tArg ) )
{
Console.WriteLine("Success: T := " + tArg.FullName);
}
if( TryGetTypeArgsOfKnownGenericType( new Generic<String>(), out Type? tArg ) )
{
Console.WriteLine("Success: T := " + tArg.FullName);
}
Footnotes:
InvalidOperationException: "Method may only be called on a Type for which Type.IsGenericParameter is true."
InvalidOperationException: "This operation is only valid on generic types."
typeof(T) is typeof(Generic<>).GetGenericArguments().Single()
It's surprising that typeof(T).ContainsGenericParameters == true when T is a generic type parameter without an argument set (i.e. T is undefined), so I'd have expected an InvalidOperationException to be thrown instead.
The documentation for ContainsGenericParameters seemingly justifies returning true (emphasis mine):
For convenience and to reduce the chance of error, the ContainsGenericParameters property provides a standard way to distinguish between closed constructed types, which can be instantiated, and open constructed types, which cannot. If the ContainsGenericParameters property returns true, the type cannot be instantiated.
Apparently using typeof(T[]) when T is a constructed generic type: the ContainsGenericParameters property is false but the GetGenericArguments() method returns a non-empty array of the type-arguments of T instead of the type-arguments of System.Array (which isn't actually a generic type).
For example:
typeof(Generic<String>[]).IsGenericType == false
typeof(Generic<String>[]).GetGenericArguments() == new[] { typeof(String) }
This is documented in the rightmost column of the above table.
And described in the documentation:
The ContainsGenericParameters property searches recursively for type parameters. For example, it returns true for an array whose elements are type A<T> even though the array is not itself generic. Contrast this with the behavior of the IsGenericType property, which returns false for arrays.

generic return type based on a Type paramater in C#

I have a class with a dictionary that maps Type keys to objects that implement some interface IWhatever.
I wish to create a generic function that gets a Type as input and returns the object mapped to that type in the dictionary.
Something like :
public T get<T>(Type type)
Where T is an instance of type and type implements IWhatever.
I don't want to return Object or even Iwhatever but objects of the given type. the type of the return objects can clearly be infered at compile time. so I assume it should be possible.
I have managed to do this in java:
public T get<T>(Class<T extends IWhatever> type) { // implementation }
Is there any way to achieve this in C# ? if not, why not and what alternatives would you suggest ?
I think you want:
public T Get<T>() where T : IWhatever { ... }
For more information, see Constraints on Type Parameters (C# Programming Guide).
This is of course only useful when the client can provide the type argument easily at compile-time. Internally, your method may need a lot of nastiness, e.g.:
return (T) myDict[typeof(T)];
I think you are being misled by Java's erasure. Consider the following Java code from your post (edited to make it valid code):
public <T extends IWhatever> T get(Class<T> type) { // implementation }
In this case, the type parameter is only required because the generic type information is only available at compile time. This is not true in C#, where you can write the following:
public T Get<T>()
where T : IWhatever
{
Type type = typeof(T);
// rest of implementation
}
From your first two sentences, what you want I think is the following. You have to decide on some attribute of your types that will be unique. You could make sure that all the types you have include the GUID attribute.
public class MyClass
{
private Dictionary<GUID, object> _myDictionary;
public AddObject(object objectToAdd)
{
_myDictionary.Add(objectToAdd.GUID, objectToAdd);
}
public object GetObject(Type typeToGet)
{
return _myDictionary[typeToGet.GUID];
}
}
If the dictionary needs to contain multiple objects of each type, then the dictionary values can be lists of objects.

Categories