I am attempting to create an extension method which generates and stores compiled Lambda Expressions for, and returns an instance of, a type of the form Class of generic type T where both Class and T are only known at runtime (driven by user selection).
I am struggling to work out the correct syntax as I am new to Expression Trees.
The "makeGenericExpression" below gives the following error when run
"Static method requires null instance, non-static method requires non-null instance."
But it's entirely possible that makeGenericLambda is also flawed (I just haven't got to it yet)
Here's what I have so far (I'm using C#4.0)
public static class TypeXtensions
{
public static object GetGenericInstance<TArg>(this Type type, TArg argument)
{
return InstanceCreationFactory<TArg>
.CreateGenericInstanceOf(type, argument);
}
private static class InstanceCreationFactory<TArg>
{
private static readonly Dictionary<Type, Func<TArg, object>> GenericInstanceCreationMethods =
new Dictionary<Type, Func<TArg, object>>();
public static object CreateGenericInstanceOf(Type type, TArg arg)
{
CacheGenericInstanceCreationMethodIfRequired(type);
return GenericInstanceCreationMethods[type].Invoke(arg);
}
private static void CacheGenericInstanceCreationMethodIfRequired(Type type)
{
if (GenericInstanceCreationMethods.ContainsKey(type)) return;
var makeGenericMI = type.GetType().GetMethod("MakeGenericType");
var paramExpression = Expression.Parameter(typeof (TArg), "argument");
var makeGenericExpression = Expression.Call(makeGenericMI, paramExpression);
// Compile the Expression into a Func which takes the type argument and returns the constructed object:
var makeGenericLambda = Expression
.Lambda<Func<TArg, object>>(makeGenericExpression)
.Compile();
GenericInstanceCreationMethods[type] = makeGenericLambda;
}
}
}
For completeness, the call I am using looks like this
private void InputDataChanged(object sender, InputConnector<IndicatorStrategy>.InputDataChangedEventArgs e)
{
var baseType = e.Payload.GetType().BaseType;
if (baseType == null) return;
var arg = baseType.GetGenericArguments()[0];
var test = typeof (ComplexIndicatorDataGenerator<>).GetGenericInstance(arg);
}
If I understand correctly what you want, you have two Type
s, let's call them T1<>
and T2
and you want to create an instance of the type T1<T2>
.
For that, you don't need any expression trees, just call MakeGenericType()
directly and then use Activator.CreateInstance()
:
public static object CreateGenericInstance(
Type genericTypeDefinition, Type genericParameter)
{
var genericType = genericTypeDefinition.MakeGenericType(genericParameter);
return Activator.CreateInstance(genericType);
}
If Activator.CreateInstance()
is too slow for you (and you should measure that it actually is too slow), then you could replace it with cached lambdas:
Dictionary<Tuple<Type, Type>, Func<object>> instanceCreatorCache
= new Dictionary<Tuple<Type, Type>, Func<object>>();
object CreateGenericInstance(Type genericTypeDefinition, Type genericParameter)
{
Func<object> instanceCreator;
var cacheKey = Tuple.Create(genericTypeDefinition, genericParameter);
if (!instanceCreatorCache.TryGetValue(cacheKey, out instanceCreator))
{
var genericType = genericTypeDefinition.MakeGenericType(genericParameter);
instanceCreator = Expression.Lambda<Func<object>>(
Expression.New(genericType)).Compile();
instanceCreatorCache[cacheKey] = instanceCreator;
}
return instanceCreator();
}
I decided to also avoid the call to MakeGenericType()
when the type is already in cache, but I have no idea whether that would actually improve performance.