使用重载构造函数从方法名称创建表达式 <Action>
Create Expression<Action> from Method name with overloaded constructor
我正在使用 Hangfire 并且有一种方法可以通过程序集、类型和方法名称来安排作业。使用默认构造函数可以正常工作,但所有方法都有重载的构造函数,这些构造函数将使用 Autofac 激活。
//Works for a default constructor
Type type = Type.GetType("typestring, assemblystring");
var method = type.GetMethod("methodstring");
Expression[] args = new Expression[] { Expression.Constant(options,typeof(Options)) }; //All methods use the same parameters
var action = Expression.Lambda<Action>(Expression.Call(Expression.New(type), method, args));
RecurringJob.AddOrUpdate(action, "cronstring");
尝试修改以支持重载构造函数(无默认值)我有此代码。
Type type = Type.GetType("typestring, assemblystring");
var method = type.GetMethod("methodstring");
Expression[] args = new Expression[] { Expression.Constant(options,typeof(Options)) }; //All methods use the same parameters
var ctor = type.GetConstructors().ToList().FirstOrDefault();
var ctorParams = ctor.GetParameters();
var ctorArgs = new Expression[ctorParams.Length];
for (int i = 0; i != ctorParams.Length; ++i)
{
ParameterExpression param = Expression.Parameter(typeof(object), ctorParams[i].Name);
ctorArgs[i] = Expression.Convert(param, ctorParams[i].ParameterType);
}
var ctorExpress = Expression.New(ctor, ctorArgs);
var action = Expression.Lambda<Action>(Expression.Call(ctorExpress, method, args));
RecurringJob.AddOrUpdate(action, "cronstring");
我收到此错误:InvalidOperationException:'System.Object' 类型的变量“{first constructor param}”从范围“”引用,但未定义
我不确定我是不是遗漏了什么或者是我做错了。我使用表达式的经验有限。
如果我没记错的话,还有另一个代码可以编译你的表达式并调用它,作为参数提供 object[]
,你必须按顺序将这些参数放入构造函数中,然后你可以使用示例代码如下:
static void Main(string[] args)
{
Type type = typeof(Foo);
var ctor = type.GetConstructor(new[] { typeof(int), typeof(string) });
var ctorParams = ctor.GetParameters();
var dynPar = Expression.Parameter(typeof(object[]), "d");
var ctorArgs = new Expression[ctorParams.Length];
for (int i = 0; i != ctorParams.Length; ++i)
{
var indVal = Expression.ArrayIndex(dynPar, Expression.Constant(i));
ctorArgs[i] = Expression.Convert(indVal, ctorParams[i].ParameterType);
}
//{ new Foo(Convert(d[0], Int32), Convert(d[1], String))}
var ctorExpress = Expression.New(ctor, ctorArgs);
//{ new Foo(Convert(d[0], Int32), Convert(d[1], String)).Run()}
var callRun = Expression.Call(ctorExpress, type.GetMethod("Run"));
//{ d => new Foo(Convert(d[0], Int32), Convert(d[1], String)).Run()}
var action = Expression.Lambda<Action<object[]>>(callRun, dynPar);
action.Compile()(new object[] { 1, "a" });
}
public class Foo
{
public Foo(int a, string b)
{
A = a;
B = b;
}
public int A { get; }
public string B { get; }
public void Run()
{
Console.WriteLine($"It is {A} and {B}");
}
}
谢谢@ASpirin,您的意见帮助解决了这个问题。我将构造函数的参数更改为 Constant
而不是 Parameter
并传入 null
.
Type type = Type.GetType("typestring, assemblystring");
var method = type.GetMethod("methodstring");
Expression[] args = new Expression[] { Expression.Constant(options,typeof(Options)) }; //All methods use the same parameters
var ctor = type.GetConstructors().ToList().FirstOrDefault();
var ctorParams = ctor.GetParameters();
var ctorArgs = new Expression[ctorParams.Length];
for (int i = 0; i != ctorParams.Length; ++i)
{
var param = Expression.Constant(null,typeof(object)); //Updated this line
ctorArgs[i] = Expression.Convert(param, ctorParams[i].ParameterType);
}
var ctorExpress = Expression.New(ctor, ctorArgs);
var action = Expression.Lambda<Action>(Expression.Call(ctorExpress, method, args));
RecurringJob.AddOrUpdate(action, "cronstring");
这是可行的,因为 Hangfire 实际上并不执行构造函数并像这样保存表达式:
//Class name is Test, method name is Run
var test = Activate<Test>();
test.Run(FromJson<Options>("REMOVED"));
Activate<Test>
在另一个程序中使用 Autofac 激活。
我正在使用 Hangfire 并且有一种方法可以通过程序集、类型和方法名称来安排作业。使用默认构造函数可以正常工作,但所有方法都有重载的构造函数,这些构造函数将使用 Autofac 激活。
//Works for a default constructor
Type type = Type.GetType("typestring, assemblystring");
var method = type.GetMethod("methodstring");
Expression[] args = new Expression[] { Expression.Constant(options,typeof(Options)) }; //All methods use the same parameters
var action = Expression.Lambda<Action>(Expression.Call(Expression.New(type), method, args));
RecurringJob.AddOrUpdate(action, "cronstring");
尝试修改以支持重载构造函数(无默认值)我有此代码。
Type type = Type.GetType("typestring, assemblystring");
var method = type.GetMethod("methodstring");
Expression[] args = new Expression[] { Expression.Constant(options,typeof(Options)) }; //All methods use the same parameters
var ctor = type.GetConstructors().ToList().FirstOrDefault();
var ctorParams = ctor.GetParameters();
var ctorArgs = new Expression[ctorParams.Length];
for (int i = 0; i != ctorParams.Length; ++i)
{
ParameterExpression param = Expression.Parameter(typeof(object), ctorParams[i].Name);
ctorArgs[i] = Expression.Convert(param, ctorParams[i].ParameterType);
}
var ctorExpress = Expression.New(ctor, ctorArgs);
var action = Expression.Lambda<Action>(Expression.Call(ctorExpress, method, args));
RecurringJob.AddOrUpdate(action, "cronstring");
我收到此错误:InvalidOperationException:'System.Object' 类型的变量“{first constructor param}”从范围“”引用,但未定义
我不确定我是不是遗漏了什么或者是我做错了。我使用表达式的经验有限。
如果我没记错的话,还有另一个代码可以编译你的表达式并调用它,作为参数提供 object[]
,你必须按顺序将这些参数放入构造函数中,然后你可以使用示例代码如下:
static void Main(string[] args)
{
Type type = typeof(Foo);
var ctor = type.GetConstructor(new[] { typeof(int), typeof(string) });
var ctorParams = ctor.GetParameters();
var dynPar = Expression.Parameter(typeof(object[]), "d");
var ctorArgs = new Expression[ctorParams.Length];
for (int i = 0; i != ctorParams.Length; ++i)
{
var indVal = Expression.ArrayIndex(dynPar, Expression.Constant(i));
ctorArgs[i] = Expression.Convert(indVal, ctorParams[i].ParameterType);
}
//{ new Foo(Convert(d[0], Int32), Convert(d[1], String))}
var ctorExpress = Expression.New(ctor, ctorArgs);
//{ new Foo(Convert(d[0], Int32), Convert(d[1], String)).Run()}
var callRun = Expression.Call(ctorExpress, type.GetMethod("Run"));
//{ d => new Foo(Convert(d[0], Int32), Convert(d[1], String)).Run()}
var action = Expression.Lambda<Action<object[]>>(callRun, dynPar);
action.Compile()(new object[] { 1, "a" });
}
public class Foo
{
public Foo(int a, string b)
{
A = a;
B = b;
}
public int A { get; }
public string B { get; }
public void Run()
{
Console.WriteLine($"It is {A} and {B}");
}
}
谢谢@ASpirin,您的意见帮助解决了这个问题。我将构造函数的参数更改为 Constant
而不是 Parameter
并传入 null
.
Type type = Type.GetType("typestring, assemblystring");
var method = type.GetMethod("methodstring");
Expression[] args = new Expression[] { Expression.Constant(options,typeof(Options)) }; //All methods use the same parameters
var ctor = type.GetConstructors().ToList().FirstOrDefault();
var ctorParams = ctor.GetParameters();
var ctorArgs = new Expression[ctorParams.Length];
for (int i = 0; i != ctorParams.Length; ++i)
{
var param = Expression.Constant(null,typeof(object)); //Updated this line
ctorArgs[i] = Expression.Convert(param, ctorParams[i].ParameterType);
}
var ctorExpress = Expression.New(ctor, ctorArgs);
var action = Expression.Lambda<Action>(Expression.Call(ctorExpress, method, args));
RecurringJob.AddOrUpdate(action, "cronstring");
这是可行的,因为 Hangfire 实际上并不执行构造函数并像这样保存表达式:
//Class name is Test, method name is Run
var test = Activate<Test>();
test.Run(FromJson<Options>("REMOVED"));
Activate<Test>
在另一个程序中使用 Autofac 激活。