介绍
我的应用程序使用方法链接实例化一个对象,因此它的生成和配置如下:
var car = new Car("Ferrari").Doors(2).OtherProperties(x = x.Color("Red"));
问题
我需要在运行时动态生成此对象 - 配置所需的链式方法将在运行时确定,因此必须动态组装所有内容。我过去曾使用反射来创建简单的对象,例如new Car("Ferrari", 2, "Red")
- 我对此很满意 - 但从来没有使用包含 lambda 表达式作为参数的链式方法 - 这两个因素真的让我卡住了。我研究了表达式树,并相信这是创建动态表达式参数的解决方案的一部分,但我完全陷入了试图弄清楚如何将其与反射缝合在一起以创建基础对象和其他链接方法的过程中。
感谢和赞赏
提前花时间查看我的问题以及您可能提供的任何指导或信息。
更新:结论
非常感谢 dasblinkenlight 和 Jon Skeet 的回答。我选择了 dasblinkenlight 的答案,因为他的代码示例让我立即启动并运行。对于方法链接,我基本上在接受的答案中使用了相同的循环方法,所以我不会重复该代码,但下面是我编写的代码,用于将表达式树方法调用动态转换为操作委托,然后可以通过反射执行,Invoke()
如dasblinkenlight 的回答。正如乔恩指出的那样,这确实是问题的症结所在。
帮助类来存储方法元数据。
public struct Argument
{
public string TypeName;
public object Value;
}
public class ExpressionTreeMethodCall
{
public string MethodName { get; set; }
public IList<Argument> Arguments { get; set; }
public ExpressionTreeMethodCall()
{
Arguments = new List<Argument>();
}
}
组装 lambda 表达式方法调用的静态方法,然后将其作为操作委托返回以在其他地方执行(Invoke()
在我的情况下作为参数传递)。
public static Action<T> ConvertExpressionTreeMethodToDelegate<T>(ExpressionTreeMethodCall methodData)
{
ParameterExpression type = Expression.Parameter(typeof(T));
var arguments = new List<ConstantExpression>();
var argumentTypes = new List<Type>();
foreach (var a in methodData.Arguments)
{
arguments.Add(Expression.Constant(a.Value));
argumentTypes.Add(Type.GetType(a.TypeName));
}
// Creating an expression for the method call and specifying its parameter.
MethodCallExpression methodCall = Expression.Call(type, typeof(T).GetMethod(methodData.MethodName, argumentTypes.ToArray()), arguments);
return Expression.Lambda<Action<T>>(methodCall, new[] { type }).Compile();
}