Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/273.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何将事件传递给C#中的函数?_C#_Delegates - Fatal编程技术网

如何将事件传递给C#中的函数?

如何将事件传递给C#中的函数?,c#,delegates,C#,Delegates,我希望将事件传递给助手函数。此函数将向事件附加一个方法。然而,我很难顺利通过这项赛事。我已尝试传递EventHandler。它进行编译,但没有附加事件(但仍然添加了事件;似乎创建了事件处理程序的副本) 例如,如果我有: public event EventHandler<EventArgs> MyEvent; 猜猜看:你试过以裁判的身份传球吗 public static void MyHelperFunction<TEventArgs>(ref EventHandler

我希望将事件传递给助手函数。此函数将向事件附加一个方法。然而,我很难顺利通过这项赛事。我已尝试传递
EventHandler
。它进行编译,但没有附加事件(但仍然添加了事件;似乎创建了事件处理程序的副本)

例如,如果我有:

public event EventHandler<EventArgs> MyEvent;

猜猜看:你试过以裁判的身份传球吗

public static void MyHelperFunction<TEventArgs>(ref EventHandler<TEventArgs> eventToAttachTo)

MyHelperFunction(ref MyEvent);
publicstaticvoidmyhelperfunction(refeventhandler eventToAttachTo)
MyHelperFunction(参考MyEvent);

这不起作用的原因是+=当应用于委托时,会创建一个新委托,该委托是新旧委托的组合。它不会修改现有委托

为了使其工作,您必须通过引用传递代理

public static void Helper(ref EventHandler<EventArgs> e)
{
    e+= (x,y) => {};
}
publicstaticvoid助手(refeventhandler e)
{
e+=(x,y)=>{};
}

这在方法之外工作的原因是因为LHS仍然是实际字段。So+=将创建一个新的委托并分配回成员字段。

我有一个解决方案,其中我有两个接口。第一个接口具有绑定某些事件的方法,而另一个接口具有可以绑定到这些事件的事件方法

第一个接口的绑定方法将第二个接口作为参数,这使得可以将事件绑定到实现第二个接口的任何类的事件方法


这是可以理解的,还是您更喜欢一些代码?:)

这不太好,但可以使用反射来实现

    public EventMonitor(object eventObject, string eventName)
    {
        _eventObject = eventObject;
        _waitEvent = eventObject.GetType().GetEvent(eventName);

        _handler = new EventHandler(SetEvent);
        _waitEvent.AddEventHandler(eventObject, _handler);
    }
其中eventObject是包含事件的对象,eventName是事件的名称。 SetEvent是您的事件处理程序

我还有这样一个dispose方法:

    public void Dispose()
    {
        _waitEvent.RemoveEventHandler(_eventObject, _handler);
    }

正如许多人指出的,将事件传递给方法不是不可能,就是不简单

  • 请澄清,但我怀疑您的预期用途如下:

    void Register()
    {
        var super = new SuperHandler();
    
        //not valid syntax:
        super.HandleEvent(MyEvent1);
        super.HandleEvent(MyEvent2);
        super.HandleEvent(MyEvent3);
        super.HandleEvent(MyEvent4);
    }
    
    您可以通过公开(或在内部,如果愿意的话)访问预期的通用事件处理程序来实现这一点:

    在本例中,我的catch-all处理程序位于静态类中,但您也可以使用非静态类。此外,我看到在您的示例中,您已经将方法设置为通用(TEventArgs)。因为所有EventHandler派生(如CancelEventHandler)都与基本EventHandler匹配,所以不需要涉及泛型(也没有帮助)

  • >P>如果注册逻辑复杂或必须保持EvEnthDunl私有,请考虑使用<强>接口事件< /强>。这可能无法达到减少代码量的预期目标,但它将允许您创建一个可以预测地处理特定类型的所有事件的类

    interface IRaiseEvents
    {
        event EventHandler ConnectionCreated;
        event EventHandler ConnectionLost;
    }
    
    public class SuperHandler
    {
        void RegisterEvents(IRaiseEvents raiser)
        {
            raiser.ConnectionCreated += (sender, args) => Console.WriteLine("Connected.");
            raiser.ConnectionLost += (sender, args) => Console.WriteLine("Disconnected.");
        }
    }
    

    刚刚想出了一个小帮手。如果是您自己创建的事件,您可以使用这样的包装器。您可以使用+=运算符正常地附加处理程序,但可以传递包装器,甚至从其他地方引发事件

    public class GenericEvent<T> where T:EventArgs
    {
        public event EventHandler<T> Source = delegate { };
    
        public void Raise(object sender, T arg = default(T))
        {
            Source(sender, arg);
        }
    
        public void Raise(T arg = default(T))
        {
            Source(this, arg);
        }
    
        public void AddHandler(EventHandler<T> handler)
        {
            Source += handler;
        }
    
        public void RemoveHandler(EventHandler<T> handler)
        {
            Source -= handler;
        }
    
        public static GenericEvent<T> operator +(GenericEvent<T> genericEvent, EventHandler<T> handler)
        {
            genericEvent.AddHandler(handler);
            return genericEvent;
        }
    }
    
    筹款活动:

    MyEvent.Raise();
    

    传递动作e=e=>myevent+=e;
    和使用处理程序从方法调用?与.NET类一起使用有好处。

    很有趣。所以我猜+=会重新创建委托(比如e=e+func)。谢谢你的帮助!我花了几个小时试图调试我的代码(将其归咎于线程),而事实上事件并没有在应该触发的时候触发。@strager,当你遇到这种情况时,最好抛出Reflector。它将解开一些误导性的语法结构,并向您展示实际发生的情况。使用ref的问题:如果使用Helper(ref myClassInstance.MyEvent),我会出现以下错误:事件MyEvent只能出现在+=或-=(从类型MyClass中使用时除外)的左侧。我如何解决这个问题呢?请注意,我只是在单元测试中这样做(所以我想我可以使用内部测试),但是有一个干净的公共解决方案也很好。我也有同样的问题。你找到解决左侧错误的方法了吗?@Strager:你介意详细说明一下你是如何使用这个的吗?我发现这个问题很有趣,但我很难看到用例。@John Feminella,我正在创建一些帮助函数,其中一个同步等待事件。它们主要用于减少我的网络类(异步操作)中几个WaitFor方法(例如WaitForConnected)的代码重用。一个很好的简单类。为了使它更复杂,我建议使用订阅事件的事件列表。如果释放GenericEvent对象,它将取消订阅所有订阅的事件。这可能意味着GenericEvent实现IDisposable接口。你说得对。如果我必须解决这个问题,我现在可能会这么做四年前,当我对C#不太了解时,我问了这个问题。不过,感谢您添加您的答案;我相信这将有助于在未来的人@凯兰-打败了我。那是三年半前的事了。
    interface IRaiseEvents
    {
        event EventHandler ConnectionCreated;
        event EventHandler ConnectionLost;
    }
    
    public class SuperHandler
    {
        void RegisterEvents(IRaiseEvents raiser)
        {
            raiser.ConnectionCreated += (sender, args) => Console.WriteLine("Connected.");
            raiser.ConnectionLost += (sender, args) => Console.WriteLine("Disconnected.");
        }
    }
    
    public class GenericEvent<T> where T:EventArgs
    {
        public event EventHandler<T> Source = delegate { };
    
        public void Raise(object sender, T arg = default(T))
        {
            Source(sender, arg);
        }
    
        public void Raise(T arg = default(T))
        {
            Source(this, arg);
        }
    
        public void AddHandler(EventHandler<T> handler)
        {
            Source += handler;
        }
    
        public void RemoveHandler(EventHandler<T> handler)
        {
            Source -= handler;
        }
    
        public static GenericEvent<T> operator +(GenericEvent<T> genericEvent, EventHandler<T> handler)
        {
            genericEvent.AddHandler(handler);
            return genericEvent;
        }
    }
    
    public GenericEvent<EventArgs> MyEvent = new GenericEvent<EventArgs>();
    
    MyEvent += (s,e) => {};
    
    MyEvent.Raise();