无法使用表达式创建生成器
Cannot Create Generator using Expressions
我有:
public class HubGroup: HubObject
{
public HubGroup(elnGroup group)
{//do stuff}
}
public class elnGroup: elnObject
{
//has properties
}
我的要求是当我为一个方法提供 2 种类型时,它将生成一个函数,该函数将接受 elnGroup 的对象作为参数和 return HubGroup 的新实例。我尝试了很多东西,但我找不到可以快速完成的方法(这些生成器函数将 运行 几次)
我知道你会说使用泛型,但我的类型是在运行时生成的。我所拥有的只是我可以明确声明的两种类型的基础类。您在下面看到的代码是我的一些片段,只是为了让您了解我正在发生的事情。
所以我这样称呼它:
public class ApiDataHandler
{
//this will be called by a method to give json content for objEln
public void SoFunny<T>(string strContent, T objHub) where T : HubObject
{
if (typeof(T) == typeof(HubGroup))
{
if (string.IsNullOrEmpty(strContant))
{
throw new Exception("Cannot parse null/empty string! ---ApiDataHandler---");
}
var objEln = JsonConvert.DeserializeObject<elnGroup>(strContant);
GetHubObjectGenerator(objEln.GetType(), objHub.GetType());
}
}
}
我要创建的内容:
Func<object,object> generator = (input) => {var bObj = input as BObject;
var aObj = new AObject(bObj);
return aObj;
}
我已经这样做了:但它一直在说:
InvalidOperationException:'ElnHub.HubObjectModel.elnGroup' 类型的变量 'objEln' 从范围 '' 引用,但未定义
//also inside ApiData Handler class
public Func<object, object> GetHubObjectGenerator(Type elnObjectType, Type hubObjectType)
{
ParameterExpression inputParam = Expression.Parameter(typeof(object), "input");
ParameterExpression objCastedAsEln = Expression.Parameter(elnObjectType, "objEln");
ParameterExpression objHub = Expression.Parameter(hubObjectType, "objHub");
var cast = Expression.TypeAs(inputParam, elnObjectType);
var assignCast = Expression.Assign(objCastedAsEln, cast);
var constructor = hubObjectType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { elnObjectType }, null);
var callingConstructor = Expression.New(constructor, new[] { objCastedAsEln });
var assignNewObj = Expression.Assign(objHub, callingConstructor);
var bodyBlock = Expression.Block(new[] { inputParam },
assignCast,
assignNewObj,
objHub
);
var l = Expression.Lambda<Func<object, object>>(
bodyBlock,
inputParam
);
Func<object, object> HubObjectGenerator = l.Compile();
return HubObjectGenerator;
}
我也试过发送通用类型,但找不到我的方法。这里有点迷失:
public Func<T,T1> GetHubObjectGenerator<T,T1>() where T : elnObject where T1 : HubObject
{
ParameterExpression argParam = Expression.Parameter(typeof(T), "objEln");
var constructor = typeof(T1).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance,null,new[] { typeof(T) },null);
Func<T, T1> HubObjectGenerator = Expression.Lambda<Func<T, T1>>(
Expression.New(constructor, new[] { argParam, }),
argParam
).Compile();
return HubObjectGenerator;
}
你想写这样的东西:
Func<object,object> generator = (input) =>
{
return new AObject((BObject)input);
}
你需要这样的东西:
public Func<object, object> GetHubObjectGenerator(Type elnObjectType, Type hubObjectType)
{
var inputParameter = ExpressionParameter(typeof(object), "input");
var castInput = Expression.Convert(inputParameter, elnObjectType);
var constructor = hubObjectType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { elnObjectType }, null);
var instantiation = Expression.New(constructor, castInput);
var lambda = Expression.Lambda<Func<object, object>>(instantiation, inputParameter);
return lambda.Compile();
}
您也可以在这里轻松使用泛型,甚至不需要强制转换:
public Func<THub, TEln> GetHubObjectGenerator<THub, TEln>() where THub : HubObject, TEln : elnObject
{
var inputParameter = ExpressionParameter(typeof(TEln), "input");
var constructor = typeof(THub).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(TEln) }, null);
var instantiation = Expression.New(constructor, inputParameter);
var lambda = Expression.Lambda<Func<THub, TEln>>(instantiation, inputParameter);
return lambda.Compile();
}
这里我没有使用变量或Expression.Block
,因为没有必要。如果确实要创建中间变量,请使用 Expression.Variable
(Expression.Parameter
仅用于输入参数)。类似于:
public Func<object, object> GetHubObjectGenerator(Type elnObjectType, Type hubObjectType)
{
var inputParameter = ExpressionParameter(typeof(object), "input");
var castInputVar = Expression.Variable(elnObjectType, "eln");
var castInput = Expression.Convert(inputParameter, elnObjectType);
var castInputAssign = Expression.Assign(castInputVar, castInput);
var constructor = hubObjectType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { elnObjectType }, null);
var hubObjectVar = Expression.Variable(hubObjectType, "hub");
var instantiation = Expression.New(constructor, castInputVar);
var hubObjectAssign = Expression.Assign(hubObjectVar, instantiation);
var block = Expression.Block(new[] { castInputVar, hubObjectVar },
castInputAssign,
hubObjectAssign,
hubObject);
var lambda = Expression.Lambda<Func<object, object>>(block, inputParameter);
return lambda.Compile();
}
我有:
public class HubGroup: HubObject
{
public HubGroup(elnGroup group)
{//do stuff}
}
public class elnGroup: elnObject
{
//has properties
}
我的要求是当我为一个方法提供 2 种类型时,它将生成一个函数,该函数将接受 elnGroup 的对象作为参数和 return HubGroup 的新实例。我尝试了很多东西,但我找不到可以快速完成的方法(这些生成器函数将 运行 几次)
我知道你会说使用泛型,但我的类型是在运行时生成的。我所拥有的只是我可以明确声明的两种类型的基础类。您在下面看到的代码是我的一些片段,只是为了让您了解我正在发生的事情。
所以我这样称呼它:
public class ApiDataHandler
{
//this will be called by a method to give json content for objEln
public void SoFunny<T>(string strContent, T objHub) where T : HubObject
{
if (typeof(T) == typeof(HubGroup))
{
if (string.IsNullOrEmpty(strContant))
{
throw new Exception("Cannot parse null/empty string! ---ApiDataHandler---");
}
var objEln = JsonConvert.DeserializeObject<elnGroup>(strContant);
GetHubObjectGenerator(objEln.GetType(), objHub.GetType());
}
}
}
我要创建的内容:
Func<object,object> generator = (input) => {var bObj = input as BObject;
var aObj = new AObject(bObj);
return aObj;
}
我已经这样做了:但它一直在说:
InvalidOperationException:'ElnHub.HubObjectModel.elnGroup' 类型的变量 'objEln' 从范围 '' 引用,但未定义
//also inside ApiData Handler class
public Func<object, object> GetHubObjectGenerator(Type elnObjectType, Type hubObjectType)
{
ParameterExpression inputParam = Expression.Parameter(typeof(object), "input");
ParameterExpression objCastedAsEln = Expression.Parameter(elnObjectType, "objEln");
ParameterExpression objHub = Expression.Parameter(hubObjectType, "objHub");
var cast = Expression.TypeAs(inputParam, elnObjectType);
var assignCast = Expression.Assign(objCastedAsEln, cast);
var constructor = hubObjectType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { elnObjectType }, null);
var callingConstructor = Expression.New(constructor, new[] { objCastedAsEln });
var assignNewObj = Expression.Assign(objHub, callingConstructor);
var bodyBlock = Expression.Block(new[] { inputParam },
assignCast,
assignNewObj,
objHub
);
var l = Expression.Lambda<Func<object, object>>(
bodyBlock,
inputParam
);
Func<object, object> HubObjectGenerator = l.Compile();
return HubObjectGenerator;
}
我也试过发送通用类型,但找不到我的方法。这里有点迷失:
public Func<T,T1> GetHubObjectGenerator<T,T1>() where T : elnObject where T1 : HubObject
{
ParameterExpression argParam = Expression.Parameter(typeof(T), "objEln");
var constructor = typeof(T1).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance,null,new[] { typeof(T) },null);
Func<T, T1> HubObjectGenerator = Expression.Lambda<Func<T, T1>>(
Expression.New(constructor, new[] { argParam, }),
argParam
).Compile();
return HubObjectGenerator;
}
你想写这样的东西:
Func<object,object> generator = (input) =>
{
return new AObject((BObject)input);
}
你需要这样的东西:
public Func<object, object> GetHubObjectGenerator(Type elnObjectType, Type hubObjectType)
{
var inputParameter = ExpressionParameter(typeof(object), "input");
var castInput = Expression.Convert(inputParameter, elnObjectType);
var constructor = hubObjectType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { elnObjectType }, null);
var instantiation = Expression.New(constructor, castInput);
var lambda = Expression.Lambda<Func<object, object>>(instantiation, inputParameter);
return lambda.Compile();
}
您也可以在这里轻松使用泛型,甚至不需要强制转换:
public Func<THub, TEln> GetHubObjectGenerator<THub, TEln>() where THub : HubObject, TEln : elnObject
{
var inputParameter = ExpressionParameter(typeof(TEln), "input");
var constructor = typeof(THub).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(TEln) }, null);
var instantiation = Expression.New(constructor, inputParameter);
var lambda = Expression.Lambda<Func<THub, TEln>>(instantiation, inputParameter);
return lambda.Compile();
}
这里我没有使用变量或Expression.Block
,因为没有必要。如果确实要创建中间变量,请使用 Expression.Variable
(Expression.Parameter
仅用于输入参数)。类似于:
public Func<object, object> GetHubObjectGenerator(Type elnObjectType, Type hubObjectType)
{
var inputParameter = ExpressionParameter(typeof(object), "input");
var castInputVar = Expression.Variable(elnObjectType, "eln");
var castInput = Expression.Convert(inputParameter, elnObjectType);
var castInputAssign = Expression.Assign(castInputVar, castInput);
var constructor = hubObjectType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { elnObjectType }, null);
var hubObjectVar = Expression.Variable(hubObjectType, "hub");
var instantiation = Expression.New(constructor, castInputVar);
var hubObjectAssign = Expression.Assign(hubObjectVar, instantiation);
var block = Expression.Block(new[] { castInputVar, hubObjectVar },
castInputAssign,
hubObjectAssign,
hubObject);
var lambda = Expression.Lambda<Func<object, object>>(block, inputParameter);
return lambda.Compile();
}