在C#中你可以设置事件的约束吗?

时间:2011-10-25 15:26:07

标签: c# events constraints

我想根据他们实现的界面限制可以订阅特定事件的类型。

即。我想要一个实现IPerson的对象“Employee”来订阅一个事件处理程序,但另一个对象“Truck”实现了一个完全不同的接口来限制。开箱即用的任何实现正确方法模式的对象都可以订阅。

我如何限制这个?

我问的原因是我正在实现Observer模式,但尝试使用C#Events。我的示例与what MSDN has here类似。

我的担心仍然是任何具有任何结构的对象(只要它包含正确的委托方法)可以在事件触发时执行。所以在我上面的例子中,一个Employee可以实现对我的例子中的对象有意义的方法,但是然后任何人都可以在上面的例子中创建另一个类 - “truck”,具有任何结构(只要它再次实现该方法)并且与主题事件联系起来...这绝对是对物体使用和良好设计的关注,也许我在这里非常挑剔,但这让我感到困扰。

3 个答案:

答案 0 :(得分:8)

这是一个非常糟糕的主意。请不要这样做。

你想要保护什么?任何“敌对”类型都可以实现界面(如果他们看不到界面,因为它在你的项目内部,那么就没有理由不把事件放在内部),所以你的黑名单并不是那么好。更糟糕的是,这会使白名单上的类型变得更难 - 他们无法轻易地将侦听器委托给“近距离”相关类型的实例。即使使用闭包(通过lambda / anonymous方法)也可能会突然中断订阅 - “呈现”订阅对象可能会成为(列入黑名单)编译器生成的类的实例。

这是一种糟糕的安全机制,它不提供编译时安全性。它并没有很好地把坏人赶出去,让好人生活困难。

无论如何,这是可能的 - 您需要为事件使用自定义实现并验证每个订阅请求。

//Please don't do this.

private EventHandler myEventField = delegate { };

// Add synchronization if required.
public event EventHandler MyEvent
{
   add
   {
      if(value.Target is IPerson)
        myEventField += value;

      else throw new ArgumentException("Subscriber must implement IPerson", "value");
   }

   remove { myEventField -= value; }
}


private void RaiseMyEvent() { myEventField(this, EventArgs.Empty); }

答案 1 :(得分:7)

  

在C#中你可以设置事件约束吗?

不。

  

我想根据他们实现的界面限制可以订阅特定事件的类型。

事件侦听器是与事件类型兼容的类型的委托实例。 “类型”不是事件的听众。

  

即。我想要一个实现IPerson的对象“Employee”来订阅一个事件处理程序,但另一个对象“Truck”实现了一个完全不同的接口来限制。

“员工”对象不会首先听取事件。侦听事件的唯一事情是委托对象

你是说你只想接受委托给那些碰巧是特定类的实例方法的方法的委托吗?这是一件非常奇怪的事情,我建议您不要尝试这样做

在编译时不可能阻止 ,但是如果你真的很想做这个奇怪的事情,你可以在运行时完成它。

为此,正如其他答案所述,您可以为事件创建加法器和卸载访问器方法,然后检查加法器,验证代理的接收者是您赞同的类型,并且如果不是,则抛出异常。

但同样,这听起来像是一个非常糟糕的主意。由听众决定他们是否对该事件感兴趣,而不是由事件来源来审查其听众。用户可以合理地期望任何兼容类型的代表都可以监听任何可访问的事件。

也许你可以解释为什么你想做这个奇怪的事情;可能有更好的方法来实现你的目标。

答案 2 :(得分:1)

我无法想象为什么你需要这个,乍一看对我来说看起来有些混乱,但无论如何你可以在事件持有者本身中封装这个限制逻辑并公开Subscribe(delegate handler)来订阅事件而不是暴露公共事件本身

class EventHolder
{
  private event EventHandler<NewUpdateEventArgs> NewUpdate;

  public void SubscribeForNewUpdates(object subscriptionOwner, 
                                     Action<NewUpdateEventArgs> callback) 
  {
     if (subscriptionOwner.GetType() == ... or subscriptionOwner is ...)
     {
        this.NewUpdate += .. subscribe callback
     }
  }
 }