Create instance of an unknown generic class Type-object at runtime?
(I'm sure this h开发者_高级运维as been answered already, I searched but couldn't find it)
I need to create an instance of several generic types during runtime. That is, I have a variable named i
that holds a number between 0-4, and I need to create an instance of the Type object for either Action<>
, Action<T1>
, Action<T1, T2>
, Action<T1, T2, T3>
or Action<T1, T2, T3, T4>
depending on what the number is (the real case is not as simple so that it really is between 0-4 and I can just use a switch statement).
Edit: Clarified that I need the Type object of the type and not an instance of the type.
The most generic way I can think of is by loading the target action type by name where the number after the backtick (aka grave accent) represents the number of generic arguments you need.
Unfortunately Action<>
is found in a different assembly (mscorlib) to the other action types so it needs to be handled differently when using this approach.
public static Type GetActionDelegateType(params Type[] typeArgs)
{
var argCount = typeArgs.Length;
if (argCount == 0) return typeof (Action);
var defType = argCount == 1
? typeof (Action<>) //special case since it's found in mscorlib
: Type.GetType(string.Format("System.Action`{0}, {1}",
argCount,
typeof (Action).Assembly.FullName));
return defType.MakeGenericType(typeArgs);
}
You can see the above code in action using this test code:
for (var i = 0; i <= 4; i++)
{
var typeArgs = Enumerable.Repeat(typeof (string), i).ToArray();
Console.WriteLine(GetActionDelegateType(typeArgs));
}
I'm not sure I quite understand what are you trying to achieve. I'll try to guess.
If you know that the needed amount of type parameters will never exceed four, you could just make an array
Type[] types = new Type[] { typeof(Action<>), typeof(Action<,>), typeof(Action<,,>) }; // omitted the rest
And provide a function
int CalculateNumberOfParameters(int i)
{
// I don't know what your i variable really means, but I suggest you have some method to determine a number of type parameters from it).
}
Then you just use types[CalculateNumberOfParameters(i)] to get your action type. Note that I provided an array of non-parameterized generics, so you should call MakeGenericType() on them to create an actual instantiable type. If you know your generic parameters beforehand (and they don't depend on i), you should specify them at type array creation.
If you can never tell how much generic parameters you will need, you will have to create types at runtime, because .net only defines Action with 0-4 parameters. You will still have to provide a conversion (or adapter) to one of the standard types, so instances of your created type can actually be useable from another parts of your application. This is a hard route, and I only had to use it once (for linq expression serialization), so I won't go deep into details unless specifically asked.
Use Activator.CreateInstance(string assembly, string classname)
.
The "assembly" could be null (in this case search in the current assembly for classes types). The "classname" shall represents the class name, which you could derive from the integer or whatever information you have.
For template classes, uses the classif string form "ClassName'T1".
Either use typeof(Action<...>)
on a class (the static way) or the GetType()
method on an instance (the dynamic way).
Not very sure what are you looking for, you never mentioned from where will you get T1,T2,T3?
This code might be of help for you.
private static void CreateAppropriateAction(params Type[] argTypes)
{
var numberOfArgs = argTypes.Count();
switch (numberOfArgs)
{
case 1:
var oneArgAction = typeof(Action<>).MakeGenericType(argTypes);
break;
case 2:
var twoArgAction = typeof(Action<,>).MakeGenericType(argTypes);
break;
case 3:
var threeArgAction = typeof(Action<,,>).MakeGenericType(argTypes);
break;
default:
//Do nothing or throw exception
break;
}
}
Then you can use this method with a call like this...
CreateAppropriateAction(typeof(string),typeof(int));
精彩评论