使用委托进行事件处理 [英] Event handling using delegates

查看:66
本文介绍了使用委托进行事件处理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个事件的简单模板,该事件将一个字符串参数添加到事件处理程序中,这是抽象的,因为它没有链接到任何UI控件。



但是,我得到了一些错误,因为作为参数指定的字符串导致了空引用,所以我可能没有正确创建事件处理程序或委托。



 使用系统; 
使用 System.Collections.Generic;
使用 System.Linq;
使用 System.Text;

命名空间 ConsoleApplication2
{
public class Class1
{
public delegate void FirstHandler( string msg);
public event FirstHandler isClassLoaded;

public Class1()
{
if this .isClassLoaded == null ){Console.WriteLine( ClassLoaded null参数); }
this .isClassLoaded( 10分);
Console.WriteLine(isClassLoaded.ToString());
}

protected void FirstHandler_EventHandler( object sender,EventArgs eventargs)
{

}

}
}

解决方案

首先需要向委托对象添加处理程序引用。请参阅C#教程,尤其是 http://msdn.microsoft.com/en -us / library / aa288459(v = vs.71).aspx [ ^ ]。


您没有使用推荐的事件声明和处理架构,旨在为其添加其他参数以统一的方式举办活动。与此同时,您正在尝试处理,即使遵循此架构;因此,您处理 EventArgs 参数,这些参数不知道您的字符串参数。此方案基于覆盖 EventArgs 类,但您尝试使用基类;难怪你不能传递这个字符串参数。



这是你可以做的:

  class  MessageEventArgs:System.EventArgs {
internal MessageEventArgs( string message){ this .Message = message; }
public string 消息{ get ; private set ; } // 这样,set只由构造函数使用,
// 并且get需要公开,由处理程序访问
} // class MessageEventArgs

class MyClass {
public System.EventHandler< MessageEventArgs> ClassLoaded; // 而不是Systen.EventHandler
void InvokeEvent( string message){
if (ClassLoaded)
ClassLoaded.Invoke( this new MessageEventArgs(message));
}
} // class MyClass





顺便说一下,你的事件名称无论如何都没有意义(一个类没有加载,但是它被实例化了),无论如何它都没有意义,因为,如果没有调用构造函数,没有代码可以向你的偶数处理程序的调用列表添加一个处理程序(它还不存在,除非它是静态的,这没什么意义),并且没有必要处理宣告类本身的事件。这就是为什么我没有重现你的构造函数 - 整个想法是错误的。



但是,让我们回到事件及其处理。使用该类的代码可以向事件处理程序的调用列表添加处理程序:

 MyClass myObject =  new  MyClass( / *   ... * / ); 
// ...
myObject.ClassLoaded + =(sender,eventArgs )= > { // 现在eventArgs类型是MessageEventArgs ,由事件类型的编译器推断
// 所以,在处理程序中你可以使用消息:
HandleTheMessageTheWayYouWant(eventArgs.Message); // 该值将从调用时刻开始传递
};





-SA


我想我需要解释一下为什么你的方法是无意义。你的代码就等同于:



  public   class  Class1 
{
// 公共代表void FirstHandler(string msg); //不需要这种类型
// 公共事件FirstHandler isClassLoaded; //不需要此事件实例

public Class1()
{
if this .isClassLoaded == null ){Console .WriteLine( ClassLoaded null参数); }
FirstHandler_EventHandler( 10 points);
Console.WriteLine(isClassLoaded.ToString());
}

protected void FirstHandler_EventHandler( string message) // 伪抽象,继承将为其添加功能
{
// ...
}

}





你明白了吗?需要事件实例来独立地处理该类的不同用户的某些事件。这些用户向事件的调用列表添加不同的句柄,并且所有这些处理程序都由事件实例的方法 Invoke 调用。处理事件在类中声明事件是完全没用的,意味着失败事件的目的。



另一个问题是类对象的实例化可以用实例(非静态)事件处理。您的活动是公开的,因此它意味着该类仍然可以拥有可以处理该事件的用户。问题是:此事件实例永远不会调用任何处理程序(除了 FirstHandler_EventHandler ,这是我之前已经解释过的无意义)。为什么?仅仅因为用户代码能够在已经获得类的实例之后为此事件添加处理程序。但在这种情况下,处理程序的添加时间太晚,因为事件实例仅在构造函数中调用。更一般地说,在构造函数中调用任何非静态(实例)事件是完全没用的。



此外,处理此类事件作为对象创作(你错误地称之为加载)原则上是无用的。当你有一段创建对象的代码片段时,这就是你的事件。想一想。



而且,仅仅是为了记录:对于静态事件实例,情况完全不同。在创建某个类的每个实例时,您可以使用类似的技术来捕获事件。这可能有一定道理,因为代码的一部分会创建一个实例,而其他一些部分会在此事件上获得通知。但是你应该明白使用任何静态成员都不是线程安全的。为了使这种技术成为线程安全的,你可以使用线程同步原语(例如锁),但是它们的使用取决于线程场景,所以我不想在这里讨论线程。例如:



  class  MyClass {
public static System.EventHandler ClassLoaded; // 警告:不是线程安全的!

public MyClass(){}
// ...
if (ClassLoaded!= null
ClassLoaded.Invoke(< span class =code-keyword> this , new EventArgs());
}

// ...

} // class MyClass

// ...

MyClass firstObject = new MyClass();
// ...
MyClass secondObject = new MyClass();

这可能是有道理的,因为每个实例的创建事件(如上所示)可以在另一个模式中处理不同的代码地点

 MyClass.ClassLoaded + =(sender,eventArgs)= >  { //  请注意,不需要实例,因为ClassLoaded是静态的,这是键 
MyClass instance =(MyClass )发送者; // 您可以确定此演员表是否成功
instance.SomeMyClassMember // 这是您访问创建的实例及其实例成员的方法
}





你现在明白了吗?



-SA

I am trying to create a simple template of an event which adds a string parameter to an event handler, which is abstract in the sense that it is not linked to any UI control.

However, I am getting something wrong because the string assigned as a parameter is resulting in a null reference, so I am probably not creating the event handler or the delegate properly.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication2
{
    public class Class1
    {
        public delegate void FirstHandler(string msg);
        public event FirstHandler isClassLoaded;

        public Class1()
        {
            if (this.isClassLoaded == null) { Console.WriteLine("ClassLoaded null argument"); }
            this.isClassLoaded("10 points"); 
            Console.WriteLine(isClassLoaded.ToString());
        }

        protected void FirstHandler_EventHandler(object sender, EventArgs eventargs)
        {
            
        }
      
    }
}

解决方案

You first need to add a handler reference to the delegate object. See the C# tutorials, especially http://msdn.microsoft.com/en-us/library/aa288459(v=vs.71).aspx[^].


You are not using the recommended event declaration and handling schema designed to add additional arguments to the event in a uniform way. At the same time, you are trying to handle the even as if this schema is followed; as a result, you deal with EventArgs parameters which "knows" nothing about your string parameter. This scheme is based on overriding EventArgs class, but you are trying to use the base class; no wonder you cannot pass this string parameter.

Here is what you can do:

class MessageEventArgs : System.EventArgs {
    internal MessageEventArgs(string message) { this.Message = message; }
    public string Message { get; private set; } // this way, set is only used by a constuctor,
                                                // and get is needed to be public, to be accessed by the handlers
} // class MessageEventArgs

class MyClass {
   public System.EventHandler<MessageEventArgs> ClassLoaded; // instead of Systen.EventHandler
   void InvokeEvent(string message) {
       if (ClassLoaded)
           ClassLoaded.Invoke(this, new MessageEventArgs(message));
   }
} // class MyClass



By the way, the name of your event makes no sense anyway (a class is not "loaded", but it is instantiated), and it makes no sense anyway, because, if a constructor is not called, no code can add a handler to the invocation list of your even handler (it does not yet exist, unless it is static, which would make too little sense), and there is no point to handle an event in the declaring class itself. That's why I did not reproduce your constructor — the whole idea is wrong.

But, let's get back to event and its handling. The code using the class can add a handler to the invocation list of an event handler:

MyClass myObject = new MyClass( /* ... */ );
//...
myObject.ClassLoaded += (sender, eventArgs) => { // now eventArgs type is MessageEventArgs, inferred by a compiler from event type
    // so, in the handler you can use Message:
    HandleTheMessageTheWayYouWant(eventArgs.Message); // the value will be passed from the moment of invocation
};



—SA


I think I need to explain more why your approach is pointless. Your code is simply equivalent to this:

public class Class1
{
        //public delegate void FirstHandler(string msg); // no need for this type
        //public event FirstHandler isClassLoaded;       // no need for this event instance
 
        public Class1()
        {
            if (this.isClassLoaded == null) { Console.WriteLine("ClassLoaded null argument"); }
            FirstHandler_EventHandler("10 points"); 
            Console.WriteLine(isClassLoaded.ToString());
        }
 
        protected void FirstHandler_EventHandler(string message) // pseudo-abstract, inheritance will add functionality to it
        {
            //...
        }
      
}



Are you getting the idea? The event instances are needed to handle some event by different users of the class independently. Those users add different handles to the invocation list of the event, and all those handlers are called by the method Invoke of the event instance. Handling the event in the class declaring the event is totally useless and means defeat of the purpose of events.

Another your problem is the idea that instantiation of the class object can be handled with an instance (non-static) event. Your event is public, so it implies the class still can have users which can handle the event. The problem is: this event instance will never call any handlers (except your FirstHandler_EventHandler, which is pointless as I already explained before). Why? Just because the user code will be able to add a handler to this event after the instance of the class is already obtained. But in this case, a handler would be added too late, as the event instance is only invoked in the constructor. More generally, invocation of any non-static (instance) events in a constructor is totally useless.

Also, handling such event as object creation (which you mistakenly call "loading") is useless in principle. When you have a fragment of code creating the object, this is your event. Just think about it.

And, just for a record: with static event instances, the situation is totally different. You can use similar technique to catch the event when every instance of some class is created. This may make some sense, because one part of code creates an instance, and some other parts get notification on this event. But you should understand that using any static members is not thread-safe. To make such technique thread-safe, you could use thread synchronization primitives (such as lock), but the use of them depends on the threading scenario, so I would prefer not to discuss threading here. For example:

class MyClass {
   public static System.EventHandler ClassLoaded; // WARNING: not thread-safe!

   public MyClass() {}
       //...
       if (ClassLoaded != null)
          ClassLoaded.Invoke(this, new EventArgs());
   }

   //...

} // class MyClass

//...

MyClass firstObject = new MyClass();
//...
MyClass secondObject = new MyClass();

It may make certain sense because the event of creation of each of the instances (like those shown above) could be handled in one more mode different places of code:

MyClass.ClassLoaded += (sender, eventArgs) => { // note that the instance is not needed because ClassLoaded is static, that's the key
   MyClass instance = (MyClass)sender; // you can be sure that this cast is successful
   instance.SomeMyClassMember // this is how you can access the created instance and its instance members
}



Are you getting the idea now?

—SA


这篇关于使用委托进行事件处理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆