Reflection - Getting the Generic Arguments from a System.Type Instance

Reflection - Getting the generic arguments from a System.Type instance

Use Type.GetGenericArguments. For example:

using System;
using System.Collections.Generic;

public class Test
{
static void Main()
{
var dict = new Dictionary<string, int>();

Type type = dict.GetType();
Console.WriteLine("Type arguments:");
foreach (Type arg in type.GetGenericArguments())
{
Console.WriteLine(" {0}", arg);
}
}
}

Output:

Type arguments:
System.String
System.Int32

Given a type instance, how to get generic type name in C#?

I see you already accepted an answer, but honestly, that answer isn't going to be enough to do this reliably if you just combine what's in there with what you already wrote. It's on the right track, but your code will only work for generic types with exactly one generic parameter, and it will only work when the generic type parameter itself is not generic!

This is a function (written as an extension method) that should actually work in all cases:

public static class TypeExtensions
{
public static string ToGenericTypeString(this Type t)
{
if (!t.IsGenericType)
return t.Name;
string genericTypeName = t.GetGenericTypeDefinition().Name;
genericTypeName = genericTypeName.Substring(0,
genericTypeName.IndexOf('`'));
string genericArgs = string.Join(",",
t.GetGenericArguments()
.Select(ta => ToGenericTypeString(ta)).ToArray());
return genericTypeName + "<" + genericArgs + ">";
}
}

This function is recursive and safe. If you run it on this input:

Console.WriteLine(
typeof(Dictionary<string, List<Func<string, bool>>>)
.ToGenericTypeString());

You get this (correct) output:

Dictionary<String,List<Func<String,Boolean>>>

Using Reflection.Emit to instantiate Generic Type with Generic Parameters

Yeah, there's definitely a trick to this. Indeed you cannot call any methods on the TypeBuilderInstantiation. Instead, TypeBuilder will let you get constructors for dependent types.

The GetConstructor method provides a way to get a ConstructorInfo object that represents a constructor of a constructed generic type whose generic type definition is represented by a TypeBuilder object.

https://msdn.microsoft.com/en-us/library/ms145822(v=vs.110).aspx

You first need the generic ConstructorInfo, gotten from typeof(List<>) in the usual way...

var listDefaultConstructor = listType.GetConstructor(new Type[0]);

and then instantiate it to your particular generic implementation:

var c = TypeBuilder.GetConstructor(list_of_T, listDefaultConstructor);

Whenever you would like to call a method on an instance of Type that represents an unconstructed/dependent type, instead look for a method with the same name in the Reflection.Emit hierarchy.


Among other things, this design pattern of passing in the generic version of the MethodInfo allows you to distinguish between calls to overloaded Class<T=int>.Foo(T) and Class<T=int>.Foo(int).

Passed an instantiated System.Type as a Type Parameter for a Generic method

To get a MethodInfo, you call Type.GetMethod:

MethodInfo method = typeof(TypeContainingMethod).GetMethod("CreateSimpleRows");
MethodInfo generic = method.MakeGenericMethod(typeArgument);

Note that if you want to get a non-public method you'll need to use the overload of GetMethod which takes a BindingFlags as well.

It's not really clear why you want to do this with reflection though. While your current snippet is repetitive, it's at least simple to understand. Using reflection is likely to make things more error-prone, and you'd still have to map typeString to a Type to start with.

Issue activating a generic type with generic array in constructor parameters

I can tell you what happens. Having a look at the resulting assembly you can see that the compiler introduces an object[] wrapping the values argument:

Activator.CreateInstance(specificType, new string[] { "foo", "bar" });
Activator.CreateInstance(specificType, new object[] { values });

Now the right overload can not be found anymore.
If you add a cast you will get the expected result and the code works again:

Activator.CreateInstance(specificType, values as string[])

But i can not tell you why this happens, maybe it can be digged out of the specs.

Create instance of generic class with dynamic generic type parameter

I found very simple solution to problem. There is no need to cast object to specific type T, just use dynamic keyword instead of casting

   Type myGeneric = typeof(MyComparer<>);
Type constructedClass = myGeneric.MakeGenericType(T);
object created = Activator.CreateInstance(constructedClass);
dynamic comparer = created; // No need to cast created object to T

and then I can use comparer normally to call its methods like:

   return comparer.Equals(myResultAsT, correctResultAsT);

According to LueTm comments, it is probably possible to use reflection again and call comparer methods, but this solution looks much easier.

Java reflection - Get actual type of T in a generic interfaceT

Close, but you need to use getGenericParameterTypes, as well as getDeclaredConstructors (since your constructor is not public):

Class<?> cls = (Class<?>) ((ParameterizedType) myClazz.class.getDeclaredConstructors()[0]
.getGenericParameterTypes()[0]) // first constructor, first parameter
.getActualTypeArguments()[0]; // first type argument

System.out.println(cls); // prints 'class otherClazz`

It should be noted that this code will only work if the type argument of the parameter is a concrete type, otherwise the cast to Class<?> will not work. For instance, in the case that the argument is a type variable, getActualTypeArguments()[0] will return an instance of TypeVariable instead of Class<...>.

How do create a Generic Object using Reflection

In order to instantiate a generic type, you need to know the actual values (types) that should be substituted for its type parameters. The GetGenericArguments() method, being a form of reflection, only gives you the type arguments, not their actual values. The values are up to you... that is the entire point of generics.

If item is a type like List<T> then item.GetGenericArguments() will return an array containing a fake "type" representing the type parameter T (with its IsGenericParameter property set to true). Therefore, passing that parameter type back into item.MakeGenericType() will simply create another open generic type equivalent to the original. To close the generic type so that it can be instantiated you need to provide an actual (non-parameter) type argument, such as int.

For example, typeof(List<>).MakeGenericType(typeof(int)) will return typeof(List<int>), while typeof(List<>).MakeGenericType(typeof(List<>).GetGenericArguments()) will simply return typeof(List<>) again. This is what is happening in your code.

I'm sorry if that is a bit opaque, I don't know how else to explain it. The bottom line is that a type like List<T> is only useful if you have a type you want to substitute in place of T.



Related Topics



Leave a reply



Submit