我有一个类EventContainer.cs,它包含一个事件,比如说:
public event EventHandler AfterSearch;
Run Code Online (Sandbox Code Playgroud)
我有另一个类,EventRaiser.cs.如何从这堂课中筹集(而不是处理)上述事件?
引发的事件将依次调用EventContainer类中的事件处理程序.这样的事情(这显然不正确):
EventContainer obj = new EventContainer();
RaiseEvent(obj.AfterSearch);
Run Code Online (Sandbox Code Playgroud)
Fem*_*ref 37
这是不可能的,事件只能从课堂内升起.如果你能做到这一点,那就会破坏事件的目的(能够从课堂内部提升状态).我认为你误解了事件的功能 - 一个事件在一个类中定义,而其他人可以通过这样做来订阅它
obj.AfterSearch += handler;(其中handler是根据签名的方法AfterSearch).一个人能够从外部订阅事件就好了,但它只能从定义它的类中升级.
hal*_*rty 25
这是可能的,但使用聪明的黑客.
灵感来自http://netpl.blogspot.com/2010/10/is-net-type-safe.html
如果您不相信,请尝试此代码.
using System;
using System.Runtime.InteropServices;
namespace Overlapping
{
[StructLayout(LayoutKind.Explicit)]
public class OverlapEvents
{
[FieldOffset(0)]
public Foo Source;
[FieldOffset(0)]
public OtherFoo Target;
}
public class Foo
{
public event EventHandler Clicked;
public override string ToString()
{
return "Hello Foo";
}
public void Click()
{
InvokeClicked(EventArgs.Empty);
}
private void InvokeClicked(EventArgs e)
{
var handler = Clicked;
if (handler != null)
handler(this, e);
}
}
public class OtherFoo
{
public event EventHandler Clicked;
public override string ToString()
{
return "Hello OtherFoo";
}
public void Click2()
{
InvokeClicked(EventArgs.Empty);
}
private void InvokeClicked(EventArgs e)
{
var handler = Clicked;
if (handler != null)
handler(this, e);
}
public void Clean()
{
Clicked = null;
}
}
class Test
{
public static void Test3()
{
var a = new Foo();
a.Clicked += AClicked;
a.Click();
var o = new OverlapEvents { Source = a };
o.Target.Click2();
o.Target.Clean();
o.Target.Click2();
a.Click();
}
static void AClicked(object sender, EventArgs e)
{
Console.WriteLine(sender.ToString());
}
}
}
Run Code Online (Sandbox Code Playgroud)
看起来你正在使用Delegate模式.在这种情况下,AfterSearch应该在EventRaiser类上定义事件,并且EventContainer类应该使用事件:
在EventRaiser.cs中
public event EventHandler BeforeSearch;
public event EventHandler AfterSearch;
public void ExecuteSearch(...)
{
if (this.BeforeSearch != null)
this.BeforeSearch();
// Do search
if (this.AfterSearch != null)
this.AfterSearch();
}
Run Code Online (Sandbox Code Playgroud)
在EventContainer.cs中
public EventContainer(...)
{
EventRaiser er = new EventRaiser();
er.AfterSearch += this.OnAfterSearch;
}
public void OnAfterSearch()
{
// Handle AfterSearch event
}
Run Code Online (Sandbox Code Playgroud)
您可以在希望事件触发的类上编写公共方法,并在调用事件时触发事件.然后,您可以从您班级的任何用户调用此方法.
当然,这个废墟封装和糟糕的设计.
我也偶然发现了这个问题,因为我正在尝试从外部调用 PropertyChanged 事件。因此,您不必在每个类中都实现所有内容。halorty 的解决方案不能使用接口工作。
我找到了一个使用重反射的解决方案。它肯定很慢,并且打破了只能从类内部调用事件的原则。但是找到这个问题的通用解决方案很有趣......
它起作用是因为每个事件都是被调用的调用方法列表。因此,我们可以获取调用列表并自行调用附加到该事件的每个侦听器。
干得好....
class Program
{
static void Main(string[] args)
{
var instance = new TestPropertyChanged();
instance.PropertyChanged += PropertyChanged;
instance.RaiseEvent(nameof(INotifyPropertyChanged.PropertyChanged), new PropertyChangedEventArgs("Hi There from anywhere"));
Console.ReadLine();
}
private static void PropertyChanged(object sender, PropertyChangedEventArgs e)
{
Console.WriteLine(e.PropertyName);
}
}
public static class PropertyRaiser
{
private static readonly BindingFlags staticFlags = BindingFlags.Instance | BindingFlags.NonPublic;
public static void RaiseEvent(this object instance, string eventName, EventArgs e)
{
var type = instance.GetType();
var eventField = type.GetField(eventName, staticFlags);
if (eventField == null)
throw new Exception($"Event with name {eventName} could not be found.");
var multicastDelegate = eventField.GetValue(instance) as MulticastDelegate;
if (multicastDelegate == null)
return;
var invocationList = multicastDelegate.GetInvocationList();
foreach (var invocationMethod in invocationList)
invocationMethod.DynamicInvoke(new[] {instance, e});
}
}
public class TestPropertyChanged : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
70978 次 |
| 最近记录: |