我正在尝试创建一个扩展方法,该方法生成并存储已编译的Lambda表达式,并返回一个类型为泛型类型T的类型的实例,其中Class和T仅在运行时已知(由用户驱动)选择)。
我正在努力找出正确的语法,因为我是Expression Trees的新手。
下面的“makeGenericExpression”在运行时会出现以下错误
“静态方法需要null实例,非静态方法需要 非空实例。“
但makeGenericLambda完全有可能也存在缺陷(我还没有完成)
这是我到目前为止所拥有的(我正在使用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;
}
}
}
为了完整性,我正在使用的电话看起来像这样
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);
}
答案 0 :(得分:3)
如果我理解你想要的是什么,你有两个Type
,我们称之为T1<>
和T2
,你想创建一个T1<T2>
类型的实例
为此,您不需要任何表达式树,只需直接调用MakeGenericType()
然后使用Activator.CreateInstance()
:
public static object CreateGenericInstance(
Type genericTypeDefinition, Type genericParameter)
{
var genericType = genericTypeDefinition.MakeGenericType(genericParameter);
return Activator.CreateInstance(genericType);
}
如果Activator.CreateInstance()
对你来说太慢了(并且你应该测量它实际上太慢了),那么你可以用缓存的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();
}
我决定在类型已经在缓存中时避免调用MakeGenericType()
,但我不知道这是否会真正提高性能。