C# 是否有理由不设立公共/内部活动发起人?

C# 是否有理由不设立公共/内部活动发起人?,c#,events,C#,Events,在典型的事件设计中,您有一个带有受保护的虚拟事件引发器的公共事件。不过,在我的项目中,我有一个主要类,它基本上充当其他几个类的管理器。有什么理由我不应该像这样设置类,这样客户端只需要订阅manager类的事件而不需要其他什么?(注意:这是根据我的实际代码即时输入的,因此请原谅任何可能的小编码错误。) 公共类管理器 { 公共事件处理程序警告; //也可以是内部的或受保护的内部的 //根据以下评论进行更新。 公共无效引发警告(IMessageSource发送方,字符串警告) { //this.War

在典型的事件设计中,您有一个带有受保护的虚拟事件引发器的公共事件。不过,在我的项目中,我有一个主要类,它基本上充当其他几个类的管理器。有什么理由我不应该像这样设置类,这样客户端只需要订阅manager类的事件而不需要其他什么?(注意:这是根据我的实际代码即时输入的,因此请原谅任何可能的小编码错误。)

公共类管理器
{
公共事件处理程序警告;
//也可以是内部的或受保护的内部的
//根据以下评论进行更新。
公共无效引发警告(IMessageSource发送方,字符串警告)
{
//this.Warning?.Invoke(发送方),new WarningEventArgs(警告);
this.Warning?.Invoke(this,new WarningEventArgs(sender,Warning);
}
}
公共班级管理
{
公共管理(经理)
{
这个。经理=经理;
}
公共管理器管理器{get;}
公开无效仅限Soyouknow()
{
这个.Manager.RaiseWarning(这个“发生了一些你应该知道的事情”);
}
}

从技术上讲,您可以这样做,但在我看来,这是一个糟糕的设计选择。事件应该通知外部订阅者在您的类的对象内部发生了什么。因此,只有定义事件的类必须知道并决定何时引发事件。

我认为,此模式可以存在,但只需稍加修改:

public class Manager: IMessenger, IMessageSender
{
   public event EventHandler<WarningEventArgs> Warning;

   // Could also be internal or protected internal
   public void RaiseWarning(object sender, string warning)
   {
      this.Warning?.Invoke(sender, new WarningEventArgs(warning);
   }
}

public interface IMessenger{
    event EventHandler<WarningEventArgs> Warning;
}    

public interface IMessageSender
{
    void RaiseWarning(object sender, string warning);
}
公共类管理器:IMessenger、IMessageSender
{
公共事件处理程序警告;
//也可以是内部的或受保护的内部的
公共无效引发警告(对象发送方,字符串警告)
{
this.Warning?.Invoke(发送方),new WarningEventArgs(警告);
}
}
公共接口IMessenger{
事件处理程序警告;
}    
公共接口IMessageSender
{
无效上升警告(对象发送器,字符串警告);
}

在这种情况下,您可以将类作为
IMessenger
提供给接收者,并将
IMessageSender
提供给消息生成器。在这种情况下,
Manager
扮演消息传递者的角色,传递给彼此不了解(也不应该了解)的类。

不,这种设计毫无意义。想象一下:

Manager mgr = new Manager();

// What if I do this?
mgr.RaiseWarning(null, "Something happened");
现在,您的
管理器
类将通知每个订阅者“发生了什么事”。因此,任何使用您的类的人都可以触发此事件,那么这有什么意义

如果我们遵循您的方法,您创建了一个带有类似这样的
单击事件的
BadButton
。即使没有单击,任何人都可以调用
单击方法

我可以把它们做成内部的吗?

如果将其设置为内部,则根据调用方的不同,他们仍然可以作为
发送者传递任何他们想要的内容。如果我使用的是
管理者
类,并且我已经订阅了该事件,我希望
发送者
的类型为
管理者
。如果您允许其他类这样做,并且您正在向我发送
null
values或
XClass
YClass
那么我就不会太高兴了。假设你订阅了
按钮
点击事件,你将
发送者转换为按钮
,它失败了,因为发送者是
员工


这就是为什么约定要创建一个proteced
OnEvent
,例如,
OnClick
OnPaint
,并允许派生类将
EventArgs
传递给它。

您正在做的事情的术语称为EventBus。如果我正确理解了您的意图,那么我可以实际更改事件decla使用强类型事件()以确保只有指定的IMessageSender才会引发事件,即
public event StrongEventHandler Warning
以及
public void RaiseWarning(IMessageSender发送方,字符串警告)
。在您的示例中,我将把
IMessageSender
替换为
IMessageSource
,因为
IMessageSender
是由管理者使用的。虽然这是传统的想法,但我想知道这与简单地将事件从管理者冒泡到管理者有何不同(除了托管类不会浪费时间实际引发只有经理可能会听的事件之外)。这就是为什么我说它可以是内部的或受保护的内部的,所以只有那些被信任不会做傻事的呼叫者才会这样做。请参阅Yuri对该方法的其他改进的回应。我想澄清的是,它不应该是公共的或内部的。您的代码使它看起来像是公共的或内部的,但它不能I don’’我不知道你俩的回答是什么。为什么不能是内部的?我想我不理解你的观点。如果一个外部客户执行了你最初示例中的代码,而RaiseWarning方法是内部的(或受保护的内部),则客户端发出自己的警告将不再可能,除非它们来自我的类,在这种情况下,没有问题。好的,我明白你现在所说的。没有理由发送者不能成为Manager对象;如果需要,我可以将RealSender添加到警告事件参数中。在这种情况下,发送者应该是仅供参考(例如,向用户报告)。调用者无意以任何方式与发送者进行交互。通过使RealSender成为一个界面,类似于我和Yuri讨论的内容,这并不违反发送者作为管理者的期望,并且界面提供的代码契约承诺的内容并不比真实发送者提供的内容多。Robin也许你的问题是我相信有更好的方法来实现它。当然你可以用这种方法来实现它,但感觉不太对劲。
Manager mgr = new Manager();

// What if I do this?
mgr.RaiseWarning(null, "Something happened");