我想要做的基本上是从事件中删除一个函数,而不知道函数的名称。
我有一个FileSystemWatcher
. 如果创建/重命名文件,它会检查其名称。如果匹配,则将其移动到特定位置。但是,如果文件被锁定,它会生成一个附加到计时器的滴答事件的 lambda,一直等到文件未被锁定。如果不是,它会移动文件,然后将自己从事件处理程序中删除。我见过很多方法可以做到这一点,比如保留实例,或者创建一个命名方法。我不能在这里做任何一个。我有哪些选择?
没有简单的方法可以实现这一点。
我不明白为什么你不能保存代表。您不必将实例保存为某个字段。它可以是由您的匿名事件处理程序捕获的局部变量:
EventHandler<TypeOfEventArgs> handler = null;
handler = (s, e) =>
{
// Do whatever you need to do here
// Remove event:
foo.Event -= handler;
}
foo.Event += handler;
我想不出一个你不能使用它的场景。
但是,如果你有这样的场景,它会变得非常棘手。
您需要找到已作为事件处理程序添加的委托。因为你没有保存它,所以很难获得它。没有this
获取当前执行方法的委托。
您也不能GetInvocationList()
在事件上使用,因为在定义它的类之外访问事件仅限于添加和删除处理程序,即+=
和-=
.
也无法创建新委托。虽然您可以访问MethodInfo
定义匿名方法的对象,但无法访问声明该方法的类的实例。此类由编译器自动生成,this
在匿名方法内部调用将返回您的常规方法在其中定义的类。
我发现可行的唯一方法是找到事件使用的字段(如果有)并调用GetInvocationList()
它。下面的代码用一个虚拟类演示了这一点:
void Main()
{
var foo = new Foo();
foo.Bar += (s, e) => {
Console.WriteLine("Executed");
var self = new StackFrame().GetMethod();
var eventField = foo.GetType()
.GetField("Bar", BindingFlags.NonPublic |
BindingFlags.Instance);
if(eventField == null)
return;
var eventValue = eventField.GetValue(foo) as EventHandler;
if(eventValue == null)
return;
var eventHandler = eventValue.GetInvocationList()
.OfType<EventHandler>()
.FirstOrDefault(x => x.Method == self)
as EventHandler;
if(eventHandler != null)
foo.Bar -= eventHandler;
};
foo.RaiseBar();
foo.RaiseBar();
}
public class Foo
{
public event EventHandler Bar;
public void RaiseBar()
{
var handler = Bar;
if(handler != null)
handler(this, EventArgs.Empty);
}
}
请注意,"Bar"
传递给的字符串必须是事件使用的字段GetField
的确切名称。这会导致两个问题:
替代方法依赖于实现细节,因此如果可以避免,请不要使用它。
使用 lambda 表达式删除事件处理程序的步骤:
public partial class Form1 : Form
{
private dynamic myEventHandler;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
myEventHandler = new System.EventHandler((sender2, e2) => this.button1_Click(sender, e, "Hi there"));
this.button1.Click += myEventHandler;
}
private void button1_Click(object sender, EventArgs e, string additionalInfo)
{
MessageBox.Show(additionalInfo);
button1.Click -= myEventHandler;
}
}