向事件处理程序发送自己的参数?

5

我正在专门使用AssemblyResolve。这是我的代码,然后是我的问题:

var a = AppDomain.CurrentDomain;
a.AssemblyResolve += new ResolveEventHandler(HandleIt);

Private Assembly HandleIt(object sender, ResolveEventArgs args){
    //Does stuff, returns an assembly
}

所以我将HandleIt添加到我的AssemblyResolve事件中。如何将它添加到该事件并传递一个参数,例如:

a.AssemblyResolve += new ResolveEventHandler(HandleIt(AnArgument));

这让我困惑了,因为HandleIt需要参数,但在将其添加到AssemblyResolve事件时没有明确传递任何参数。我期望看到像这样的内容:
a.AssemblyResolve += new ResolveEventHandler(HandleIt(aSender,someArgs));

嗯,我希望能够在将HandleIt函数添加到AssemblyResolve事件时,向其发送另一个参数。

希望这样说得清楚了,谢谢。

补充:

if(aBool){
    a.AssemblyResolve += new ResolveEventHandler(HandleA);
}
else{
    a.AssemblyResolve += new ResolveEventHandler(HandleB);
}

HandleA(object sender, ResolveEventArgs args){
    Handle(true);
}
HandleB(object sender, ResolveEventArgs args){
    Handle(false);
}
Handle(bool isA){

}

-vs-

if(aBool){
    a.AssemblyResolve += (object s, ResolveEventArgs a) => Handle(s,a,true);
}
else{
    a.AssemblyResolve += (object s, ResolveEventArgs a) => Handle(s,a,false);
}

Handle(object sender, ResolveEventArgs args, bool isA){

}

在lambda版本中,您不需要if(aBool),您可以简单地说a.AssemblyResolve += (object s, ResolveEventArgs a) => Handle(s,a,aBool);或者无论参数应该是什么。 - Rune FS
4个回答

11

当事件被触发时,如果你想绑定额外的参数,可以使用lambda表达式来实现。

var a = AppDomain.CurrentDomain;
a.AssemblyResolve += (object s,ResolveEventArgs a) => HandleIt(s,a,someArgument);

Private Assembly HandleIt(object sender, ResolveEventArgs args, SomeType arg){
    //Does stuff, returns an assembly
}

其中someArgument是您希望绑定的值。

这本质上使用lambda函数来部分应用一个函数。在其他语言中非常常见,但C#不支持直接实现。部分应用与F#和Haskell等语言中存在的柯里化紧密相关(因为该概念得名于Haskell Curry)以及其他各种函数式语言。它们的结果类型不同。

它们都与闭包(以上代码中的概念)有关,在不支持部分应用或柯里化的语言中,可以使用闭包来实现类似的功能。但是请注意,闭包与部分应用有一些差异,可能会产生一些出人意料的错误。例如:

int i = 1;
Func<int> f = () => i;
i = 2;

System.Console.WriteLine(f());

2打印到控制台。因为闭包捕获的是变量的引用而不是该变量的值。这是在for循环中关闭for循环变量时经常出现的错误。


投票支持这个选项,而不是我的答案。 - DaveShaw
这并不能帮助他手动触发事件来实现他的目标。请查看我回答中的更新。 - Daniel Hilgarth
@Daniel,在问题中哪里提到了手动触发事件的内容? - Rune FS
@sooprise 我猜这取决于你的背景以及你需要多少不同的方法来完成你所寻找的东西(一般性地说,不是针对这个问题)。 - Rune FS
好的。但我越看它,Lambda表达式就越合理。在编程中,我一直很难接受Lambda表达式,因为它们对我来说非常不直观。谢谢。 - sooprise
显示剩余2条评论

2

AppDomain.CurrentDomain会触发事件并传递参数,+=行只是向事件注册处理程序,那里的参数没有任何意义。

类比:

您向邮递员注册地址,他稍后会将邮件送到该地址。当您在邮局注册时,您不会把您想要稍后送到您的邮件交给他们!


当然,我发现我的理解甚至比之前更糟糕。也许我尝试做的事情根本就没有意义,那就是:有意触发AssemblyResolve来选择在运行时加载我的DLL。我想能够通过将参数传递给我的AssemblyResolve事件处理程序来加载这个或那个dll。这会改变什么吗? - sooprise
看看Rune FS的回答。另外,如果这就是你想做的事情,那么这应该是你的问题! - asawyer

1

这是不可能的。 在这种情况下,HandleIt是一个委托,并且必须匹配ResolveEventHandler的签名。

a.AssemblyResolve += new ResolveEventHandler(HandleIt);

在这一行中设置它只是告诉代码当AssemblyResolve被触发时执行什么,触发AssemblyResolved事件的东西将传递它的参数。您可以使用自己的参数重新引发另一个事件,并将其连接到另一个处理程序(或仅调用方法)。

编辑:或者也许你可以使用Lambda表达式 :o


这是否是“最佳实践”方法?我可以看到我可以通过lambda表达式有点混乱地添加参数。 - sooprise
这是我以前解决类似问题时所做的。不过那个 lambda 真的很方便。 - asawyer

0
稍微技术一点:您正在向事件注册委托以调用您的方法。 这与对该方法的调用不同。 这有点类似于:
Action<object, ResolveEventArgs> handleItDelegate = HandleIt;

当事件被触发时,委托将被调用。我的示例的类比如下:
handleItDelegate(sender, eventArgs);

更新:
在评论中,您澄清了您想要实现的目标:您想触发事件,以便加载您的程序集。您不能按照您认为的方式做到这一点。要手动加载程序集,只需这样做,无需使用事件。当运行时尝试解析引用的程序集但找不到它时,才会调用该事件。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接