C# 在C中从不同的类引发一个类的事件#
我有一个类EventContainer.cs,它包含一个事件,比如:C# 在C中从不同的类引发一个类的事件#,c#,events,C#,Events,我有一个类EventContainer.cs,它包含一个事件,比如: public event EventHandler AfterSearch; 我还有一门课,EventRaiser.cs。我如何从本课程中引发(而不是处理)上述事件 引发的事件将依次调用EventContainer类中事件的处理程序。类似这样(这显然是不正确的): 这是不可能的,事件只能从类内部发生。如果你能做到这一点,它将破坏事件的目的(能够从类内部提升状态更改)。我认为您误解了事件的功能——事件是在类中定义的,其他人可以
public event EventHandler AfterSearch;
我还有一门课,EventRaiser.cs。我如何从本课程中引发(而不是处理)上述事件
引发的事件将依次调用EventContainer类中事件的处理程序。类似这样(这显然是不正确的):
这是不可能的,事件只能从类内部发生。如果你能做到这一点,它将破坏事件的目的(能够从类内部提升状态更改)。我认为您误解了事件的功能——事件是在类中定义的,其他人可以通过这样做来订阅它
obj.AfterSearch+=handler
(其中handler是根据AfterSearch
签名的方法)。一个人可以从外部订阅事件,但只能从定义它的类内部发起。这是不可能的,事件只能从类内部发起。如果你能做到这一点,它将破坏事件的目的(能够从类内部提升状态更改)。我认为您误解了事件的功能——事件是在类中定义的,其他人可以通过这样做来订阅它
obj.AfterSearch+=handler
(其中handler是根据AfterSearch
签名的方法)。您可以从外部订阅事件,但只能从定义它的类的内部进行订阅。您可以在希望触发事件的类上编写公共方法,并在调用事件时触发事件。然后可以从类的任何用户调用此方法
当然,这会破坏封装,是一种糟糕的设计。您可以在希望触发事件的类上编写公共方法,并在调用事件时触发事件。然后可以从类的任何用户调用此方法 当然,这破坏了封装,是一种糟糕的设计。同意Femaref的观点——请注意,这是代表和事件之间的一个重要区别(例如,请参阅对这一区别和其他区别的详细讨论) 根据您想要实现的目标,您最好与一名代表在一起。同意Femaref的观点——请注意,这是代表和事件之间的一个重要区别(例如,请参阅对这一区别和其他区别的详细讨论)
根据您想要实现的目标,您最好有一个代表。看起来您正在使用。在这种情况下,应在
EventRaiser
类上定义AfterSearch
事件,并且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();
}
public EventContainer(...)
{
EventRaiser er = new EventRaiser();
er.AfterSearch += this.OnAfterSearch;
}
public void OnAfterSearch()
{
// Handle AfterSearch event
}
在EventContainer.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();
}
public EventContainer(...)
{
EventRaiser er = new EventRaiser();
er.AfterSearch += this.OnAfterSearch;
}
public void OnAfterSearch()
{
// Handle AfterSearch event
}
看起来你在用这个。在这种情况下,应在
EventRaiser
类上定义AfterSearch
事件,并且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();
}
public EventContainer(...)
{
EventRaiser er = new EventRaiser();
er.AfterSearch += this.OnAfterSearch;
}
public void OnAfterSearch()
{
// Handle AfterSearch event
}
在EventContainer.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();
}
public EventContainer(...)
{
EventRaiser er = new EventRaiser();
er.AfterSearch += this.OnAfterSearch;
}
public void OnAfterSearch()
{
// Handle AfterSearch event
}
有很好的方法可以做到这一点。C#中的每个事件都有一个委托,指定该事件的方法符号。使用事件委托的类型在外部类中定义字段。在外部类的构造函数中获取该字段的引用并保存它。在事件的主类中,为外部类的委托发送事件引用。现在,您可以轻松地在外部类中调用委托
public delegate void MyEventHandler(object Sender, EventArgs Args);
public class MyMain
{
public event MyEventHandler MyEvent;
...
new MyExternal(this.MyEvent);
...
}
public MyExternal
{
private MyEventHandler MyEvent;
public MyExternal(MyEventHandler MyEvent)
{
this.MyEvent = MyEvent;
}
...
this.MyEvent(..., ...);
...
}
有很好的方法可以做到这一点。C#中的每个事件都有一个委托,指定该事件的方法符号。使用事件委托的类型在外部类中定义字段。在外部类的构造函数中获取该字段的引用并保存它。在事件的主类中,为外部类的委托发送事件引用。现在,您可以轻松地在外部类中调用委托
public delegate void MyEventHandler(object Sender, EventArgs Args);
public class MyMain
{
public event MyEventHandler MyEvent;
...
new MyExternal(this.MyEvent);
...
}
public MyExternal
{
private MyEventHandler MyEvent;
public MyExternal(MyEventHandler MyEvent)
{
this.MyEvent = MyEvent;
}
...
this.MyEvent(..., ...);
...
}
这是可能的,但使用聪明的黑客 灵感来自 如果您不相信,请尝试此代码
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());
}
}
}
这是可能的,但使用聪明的黑客 灵感来自 如果您不相信,请尝试此代码
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());
}
}
}
我也有类似的困惑,老实说,我发现这里的答案令人困惑。尽管有几个人暗示我以后会发现解决办法是可行的 我的解决方案是熟悉书本,更加熟悉委托和事件处理程序。 虽然我已经用了很多年了,但我从来都不熟悉它们。 给出了我所读过的委托和事件处理程序的最佳解释,并清楚地解释了一个类可以是事件的发布者,也可以让其他类使用它们。 本文:讨论如何将事件单次强制转换为一个处理程序,因为根据定义委托是多播的。委托继承system.MulticastDelegate大多数(包括系统委托)都是多播的。 我发现多播意味着任何具有相同签名的事件处理程序都将接收引发的事件。多播行为让我有些不眠之夜,因为我一步一步地浏览代码,看到我的事件似乎被错误地发送给处理程序,而我根本不想得到这个事件。这两篇文章都解释了这种行为。 第二篇文章向您展示了一种方式,第一篇文章向您展示了另一种方式,即使委托和签名严格键入。 我个人认为,强大的打字可以防止愚蠢的错误,这可能是一个痛苦的发现。所以我会投票支持第一篇文章,即使我让第二篇文章的代码正常工作。我只是好奇而已。:-) 我也很好奇,我是否能让#2篇文章的代码表现得像我对上面原始问题的解释一样。不管你选择什么方法,或者如果我也误解了最初的问题,我真正想要传达的信息是,我仍然认为你会从阅读中受益
class Program
{
static void Main(string[] args)
{
MyExtension ext = new MyExtension();
ext.MyEvent += ext_MyEvent;
ext.Dosomething();
Console.ReadLine();
}
static void ext_MyEvent(object sender, int num)
{
Console.WriteLine("Event fired.... "+num);
}
}
public class MyExtension
{
public event EventHandler<int> MyEvent;
public void Dosomething()
{
int no = 1;
if (MyEvent != null)
MyEvent(this, ++no);
}
}
}
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;
}
public delegate void AllocationService_RaiseAllocLog(string orderNumber, string message, bool logToDatabase);
public delegate void AllocationService_RaiseAllocErrorLog(string orderNumber, string message, bool logToDatabase);
public class AllocationService { ...
public event AllocationService_RaiseAllocLog RaiseAllocLog;
public event AllocationService_RaiseAllocErrorLog RaiseAllocErrorLog;
RaiseAllocErrorLog(SOHNUM_0, ShipmentGenerated + ": Allocated line QTY was: " + allocatedline.QTY_0 + ", Delivered was: " + QTY_0 + ". Problem batch.", false);
private void PickGenLibrary_RaiseAllocLog(string orderNumber, string message, bool updateDB)
{
RaiseLog(orderNumber, message, false);
}
private void PickGenLibrary_RaiseAllocErrorLog(string orderNumber, string message, bool updateDB)
{
RaiseErrorLog(orderNumber, message, false);
}
AllocationService allsvc = new AllocationService(PickResult);
allsvc.RaiseAllocLog += new AllocationService_RaiseAllocLog(PickGenLibrary_RaiseAllocLog);
allsvc.RaiseAllocErrorLog += new AllocationService_RaiseAllocErrorLog(PickGenLibrary_RaiseAllocErrorLog);
public delegate void JPPAPickGenLibrary_RaiseLog(string orderNumber, string message, bool logToDatabase);
public delegate void JPPAPickGenLibrary_RaiseErrorLog(string orderNumber, string message, bool logToDatabase);