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 aConstructorInfo
object that represents a constructor of a constructed generic type whose generic type definition is represented by aTypeBuilder
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
C# Covariant Return Types Utilizing Generics
How to Detect Keypress While Not Focused
Order of Serialized Fields Using JSON.Net
Closing Excel Application Process in C# After Data Access
How to De-Elevate Privileges for a Child Process
How to Use Enumwindows to Find Windows with a Specific Caption/Title
How to Iterate Over the Properties of an Anonymous Object in C#
Use Linq to Group a Sequence of Numbers with No Gaps
Mutating the Expression Tree of a Predicate to Target Another Type
Format Number Like Stack Overflow (Rounded to Thousands with K Suffix)
Namespace' But Is Used Like a 'Type'
How to Extract a File from an Embedded Resource and Save It to Disk