我有一个解决方案,我想建立一组通过Hangfire运行的Method调用。我想编写一个遍历集合的注册类,并创建RecurringJobs。
我有代码可以在其中指示静态Action
方法的表达式起作用,并创建Action静态方法的表达式。
假设我有以下代码:
public static class Test
{
public static void Test1() {}
public static void Test2() {}
public static void Test3(IDependency dependency) {}
public static void Test4(IDependency dependency) {}
public static void TestWrapper(Action<IDependency> test)
{
IDependency dependency = ExternalMethodToFetchFromIOC();
test(dependency);
}
public static IDependency ExternalMethodToFetchFromIOC()
{
return new Dependency();
}
}
注册Action
方法时一切正常:
public static class HangfireReg
{
public static void RegisterThings()
{
List<Action> collection = new List<Action>
{
Test.Test1,
Test.Test2,
}
foreach(Action action in collection)
{
BackgroundJob.Enqueue(() => action);
}
}
}
在依赖注入方面遇到麻烦;如果我使用一种方法来包装调用,则Hangfire会抱怨:
作业方法参数中不支持匿名函数,委托和lambda表达式:很难序列化它们及其所有作用域。
public static class HangfireReg
{
public static void RegisterThings()
{
List<Action<IDependency>> collection = new List<Action<IDependency>>
{
Test.Test3,
Test.Test4,
}
foreach(Action<IDependency> action in collection)
{
BackgroundJob.Enqueue(() => Test.TestWrapper(action));
}
}
}
最后,如果我尝试使用显式类型手动构建Lambda表达式,则会遇到另一个错误(我当时想我可以绕过Type
及其MethodInfo
进行注册,而不是):
从范围''引用的类型为'IDependency'的'variable'dependency',但未定义'
public static class HangfireReg
{
public static void RegisterThings()
{
{
Type targetType = typeof(Test);
MethodInfo testMethod = targetType.GetMethod(nameof(Test.Test4), BindingFlags.Static | BindingFlags.Public);
MethodInfo fetchDependency = targetType.GetMethod(nameof(Test.ExternalMethodToFetchFromIOC), BindingFlags.Static | BindingFlags.Public);
//IDependency dependency = Test.ExternalMethodToFetchFromIOC();
ParameterExpression dependencyVar = Expression.Variable(typeof(IDependency), "dependency");
MethodCallExpression call = Expression.Call(fetchDependency);
BinaryExpression assignedInstance = Expression.Assign(dependencyVar, call);
//Test.Test4(dependency);
MethodCallExpression invoke = Expression.Call(testMethod, assignedInstance);
//{ IDependency dependency = Test.ExternalMethodToFetchFromIOC(); Test.Test4(dependency); }
Expression<Action> action = Expression.Lambda<Action>(invoke);
BackgroundJob.Enqueue(action);
}
}
}
(对于它的价值,这就是Lambda的外观,被视为DebugView):
.Lambda #Lambda1<System.Action>()
{
.Call Test.Test4
(
$config = .Call Test.ExternalMethodToFetchFromIOC()
)
}
Hangfire的依赖项注入需要一个通用类型,该类型需要在编译时就知道,并且需要调用该类型的方法之一,因此我不能在集合中真正使用Type
。 / p>
我是否有任何方法可以在Action<IDependency>
的动态集合上进行迭代,而无需在入队时知道IDependency
的值,因此IoC的 some 模式可以注入参数?
编辑:更正lambda以达到我的预期。
我收到一个新错误:
表达式主体应为
MethodCallExpression
类型:
public static class HangfireReg
{
public static void RegisterThings()
{
{
Type targetType = typeof(Test);
MethodInfo testMethod = targetType.GetMethod(nameof(Test.Test4), BindingFlags.Static | BindingFlags.Public);
MethodInfo fetchDependency = targetType.GetMethod(nameof(Test.ExternalMethodToFetchFromIOC), BindingFlags.Static | BindingFlags.Public);
//IDependency dependency = Test.ExternalMethodToFetchFromIOC();
ParameterExpression dependencyVar = Expression.Variable(typeof(IDependency), "dependency");
MethodCallExpression call = Expression.Call(fetchDependency);
BinaryExpression assignedInstance = Expression.Assign(dependencyVar, call);
//Test.Test4(dependency);
MethodCallExpression invoke = Expression.Call(testMethod, dependencyVar);
//{ IDependency dependency = Test.ExternalMethodToFetchFromIOC(); Test.Test4(dependency); }
BlockExpression fullCall = Expression.Block(assignedInstance, invoke);
Expression<Action> action = Expression.Lambda<Action>(fullCall);
BackgroundJob.Enqueue(action);
}
}
}
产生以下结果的一个lambda:
.Lambda #Lambda1<System.Action>() {
.Block() {
$dependency = .Call Test.ExternalMethodToFetchFromIOC();
.Call Test.Test4($dependency)
}
}