代表元:一个代表元封装了具有一些标志的一个方法。基本上,代表元是类型安全和函数指针的安全版本(回调功能)。可以同时在一个代表元实例中同时封装静态和实例方法。
尽管你可以象使用方法一样使用代表,但它的主要用途在于运用类的事件
类:一个类类型可以包含数据成员、函数成员和嵌套类型。数据成员是常量、字段和事件。函数成员包括方法、属性、索引、操作符、构造函数和析构函数。
事件:当你写一个类时,有时有必要让类的客户知道一些已经发生的事件。如果你是一个具有多年编程经验的程序员,似乎有很多的解决办法,包括用于回调的函数指针和用于ActiveX控件的事件接收(event sinks)。现在你将要学到另外一种把客户代码关联到类通知的办法——使用事件。
事件既可以被声明为类域成员(成员变量),也可以被声明为属性。两者的共性为,事件的类型必定是代表元,而函数指针原形和C#的代表元具有相同的含义。
每一个事件都可以被0或更多的客户占用,且客户可以随时关联或取消事件。你可以以静态或者以实例方法定义代表元,而后者很受C++程序员的欢迎摘自:《展现C#》

解决方案 »

  1.   

    代表元就是代理吧:〉
    代理类似于COM的代理,所谓代理就是要将所要执行的操作按照自身的情况从新定义,然后统一由一种事件来激发执行(这只是代理的一种典型用途)。实质上,代理是函数的指针(如果你是C++程序员对此就不陌生了)事件,简单一点就是由用户激发的,由计算机响应的一种消息交互机制。在C#中很多的事件可以由用户激发,然后可以通过创建代理的方法来实现事件的个性化。类,就是面向对象中的基本概念呀。打个比方,如果物质可以看作一个类的话,应该具有的属性是质量,体积,密度等等,在这里面还可以对质量、体积、密度等作些测量。前者就是所谓的数据成员,后者就是成员函数。 其实,类和一般意义上的类没有本质的区别,只不过在叫法上少有差别。比如人、动物是物质的两种形式,那么在面向对象里面,就叫做物质的两个子类。这就叫做继承。类还有很多特性,不妨看看面向对象的书,做个全面深刻的了解:〉
      

  2.   

    Working With C#  
     
    by Eric GunnersonAn Event to Remember
    April 15, 2001    To be archived May 17, 2001 Download the sample code for this column.A Bit of Review
    Last month, we talked about performance and boxing. One of the questions that came up from a reader was why the Perl version is so much faster than the C# version. One answer is that Perl is very good at what it does. One reader pointed out that I had forgotten to tell the Regex to compile the regular expression rather than interpret it on every match. In Beta 1, this is done by passing "c" as the second parameter to the Regex constructor (there's an enum to do the same thing in Beta 2). This cuts the overhead nearly in half, and reduces the elapsed time for the fastest version down to a little less than 7 seconds. Delegates and Events
    The subject of this month's column is delegates and events. Well, just delegates, actually, since events will be next month. I'll start by explaining what delegates are, what they can do, and how they are used, and then we'll cover events next month. Delegates
    In most cases, when we call a function, we specify the function to be called directly. If the class MyClass has a function named Process, we'd normally call it like this:MyClass myClass = new MyClass();
    myClass.Process();That works well in most situations. Sometimes, however, we don't want to call a function directly—we'd like to be able to pass it to somebody else so that they can call it. This is especially useful in an event-driven system such as a graphical user interface, when I want some code to be executed when the user clicks on a button, or when I want to log some information but can't specify how it is logged.Consider the following example:public class MyClass
    {
       public void Process()
       {
          Console.WriteLine("Process() begin");
          // other stuff here…
          Console.WriteLine("Process() end");
       }
    }In this class, we're doing some logging to let us know when the function begins and ends. Unfortunately, our logging is hardwired to go only to the console, which might not be what we want. What we'd really like is a way to be able to control where the information is logged from outside the function, without having to complicate the function code.A delegate is perfect for this use; it will allow us to specify what the function we'll be calling looks like without having to specify which function to call. The declaration for a delegate looks just like the declaration for a function, except that in this case, we're declaring the signature of functions that this delegate can reference. For our example, we'll declare a delegate that takes a single string parameter and has no return type. Our class is modified as follows:public class MyClass
    {
       public delegate void LogHandler(string message);
       public void Process(LogHandler logHandler)
       {
          if (logHandler != null)
             logHandler("Process() begin");
          // other stuff here…
          if (logHandler != null)
             logHandler ("Process() end");
       }
    }The use of the delegate is just like calling a function directly, though we need to add a check to see if the delegate is null (that is, not pointing to a function) before calling the function.To call the Process() function, we need to declare a logging function that matches the delegate, and then create an instance of the delegate, pointing to the function. This delegate will then be passed to the Process() function.class Test
    {
       static void Logger(string s)   {
          Console.WriteLine(s);
       }   public static void Main()
       {
          MyClass myClass = new MyClass();      MyClass.LogHandler lh = new MyClass.LogHandler(Logger);
       
          myClass.Process(lh);
       }
    }The Logger() function is the one that we want to be called from the Process() function, and it's declared so that it matches the delegate. In Main(), we create an instance of the delegate, and pass the delegate constructor the function to which we want it to point. Finally, we pass the delegate to the Process() function, which can then call the Logger() function.If you're from the C++ world, you'll probably think that a delegate is a lot like a function pointer, and you'd be fairly close. However, a delegate isn't just a function pointer; it provides more functionality as well. Passing State
    In the simple example above, the Logger() function merely writes the string out. A different function might want to log the information to a file, but to do this, the function needs to know what file to write the information to. In the Win32® world, when you pass a function pointer, you can pass the state along with it. In C#, however, this isn't necessary because delegates can refer to either static or member functions. Here's an example of how to refer to a member function:class FileLogger
    {
       FileStream fileStream;
       StreamWriter streamWriter;   public FileLogger(string filename)
       {
          fileStream = new FileStream(filename, FileMode.Create);
          streamWriter = new StreamWriter(fileStream);
       }   public void Logger(string s)
       {
          streamWriter.WriteLine(s);
       }   public void Close()
       {
          streamWriter.Close();
          fileStream.Close();
       }
    }
    class Test
    {
       public static void Main()
       {
          FileLogger fl = new FileLogger("process.log");
          
          MyClass myClass = new MyClass();      MyClass.LogHandler lh = new MyClass.LogHandler(fl.Logger);
       
          myClass.Process(lh);
          fl.Close();
       }
    }The FileLogger class merely encapsulates the file. Main() is modified so that the delegate points to the Logger() function on the fl instance of a FileLogger. When this delegate is invoked from Process(), the member function is called and the string is logged to the appropriate file.The cool part here is that we didn't have to change the Process() function; the code to all the delegate is the same regardless of whether it refers to a static or member function.Multicasting
    Being able to point to member functions is nice, but there are more tricks you can do with delegates. In C#, delegates are multicast, which means that they can point to more than one function at a time (that is, they're based off the System.MulticastDelegate type). A multicast delegate maintains a list of functions that will all be called when the delegate is invoked. We can add back in the logging function from the first example, and call both delegates. To combine two delegates, we use the Delegate.Combine() function. Here's what the code looks like:      MyClass.LogHandler lh = (MyClass.LogHandler) 
             Delegate.Combine(new Delegate[] 
                {new MyClass.LogHandler(Logger),
                new MyClass.LogHandler(fl.Logger)});Wow, that's ugly! Rather than force this syntax on the user, C# provides a nicer syntax. Rather than calling Delegate.Combine(), you can simply use += to combine the two delegates:      MyClass.LogHandler lh = null;
          lh += new MyClass.LogHandler(Logger);
          lh += new MyClass.LogHandler(fl.Logger);That's a lot cleaner. To remove a delegate from a multicast delegate, Delegate.Remove() can be called, or the -= operator can be used (I know which one I'll use).When you call a multicast delegate, the delegates in the invocation list are called synchronously in the order in which they appear. If an error occurs during this process, the execution process is interrupted.If you want to control the invocation order more closely—if you want guaranteed invocation, for example—you can get the invocation list from the delegate and invoke the functions yourself. Here's what that would look like:foreach (LogHandler logHandler in lh.GetInvocationList())
    {
       try
       {
          logHandler(message);
       }
       catch (Exception e)
       {
          // do something with the exception here…
       }
    }The code merely wraps each invocation in a try-catch so that an exception thrown in one handler won't prevent the other handlers from being called. Events
    Now that we've spent some time on delegates, it's time to move onto events. An obvious question is "why do we need events, if we have delegates?"The best way to answer this is to consider the case of an event on a user interface object. A button, for example, could have a public Click delegate on it. We could hook up a function to that delegate, and then the button would call the delegate when it was clicked. We'd do something like:   Button.Click = new Button.ClickHandler(ClickFunction);Which means ClickFunction() will be called when the button is clicked. Quiz: Is there a problem with the code above? What have we forgotten?The answer is that we forgot to use +=, and instead assigned the delegate directly. That means that any other delegate that was hooked up to Button.Click is now unhooked. Button.Click needs to be public so that other objects can access it, and there's no way to prevent the above scenario. Similarly, to remove a delegate a user could write:   Button.Click = null;And that would remove all delegates. These situations are particularly bad because in many cases, there is only one delegate hooked up, and the problem isn't visible as a bug. Later on, another delegate is hooked up, and things start breaking.Events add a layer of protection on top of the delegate model. Here's an example of an object that supports an event:public class MyObject
    {
       public delegate void ClickHandler(object sender, EventArgs e);
       public event ClickHandler Click;   protected void OnClick()
       {
          if (Click != null)
             Click(this, null);
       }
    }The ClickHandler delegate defines the signature of the event using the standard pattern for event delegates. It has a name that ends in handler, and it has two parameters. The first parameter is the object that sent the object, and the second parameter is used to pass the information that goes along with the event. In this case, there's no information to pass, so EventArgs is used directly, but a class derived from EventArgs (such as MouseEventArgs) is used when there is data to pass.The declaration of the Click event does two things. First, it declares a delegate member variable named Click that is used from within the class. Second, it declares an event named Click that can be used from outside the class, subject to the usual accessibility rules (in this case, the event is public). A function like OnClick() is normally included so that the type or derived types can fire the event, and you'll notice that the code it uses to fire the event is the same as the code for delegates, because Click is a delegate. Just like a delegate, we hook and unhook from an event using += and -=, but unlike a delegate, those operations are the only ones that can be performed on an event. This ensures that the two mistakes discussed previously can't occur.Using an event is straightforward. class Test
    {
       static void ClickFunction(object sender, EventArgs args)
       {
          // process the event here.
       }
       public static void Main()
       {
          MyObject myObject = new MyObject();      myObject.Click += new MyObject.ClickHandler(ClickFunction);      
       }
    }We create a static function or a member function that matches the signature of the delegate, and then add a new instance of the delegate to the event with +=. 
      

  3.   

    举个代表元的例子:
    class Mainclass
    {
       delegate void Mydelegate();
       class Myclass
      {
         public static void Mymethod1()
         {
              Console.WriteLine("I'm Mymethod1!");
         }
         public static void Mymethod2()
         {
              Console.WriteLine("I'm Mymethod2!");
         }
      }
      public static void Main()
      {
         Mydelegate P=new Mydelegate();
         p(Myclass.Mymethod1);
         p();
         p(Myclass.Mymethod2);
         p();  
      }
    }
    output:
    I'm Mymethod1!
    I'm Mymethod2!
    好象代表元的类型和所指方法类型必须一致
      

  4.   

    上面的大块头E文中有4个经典的例子。。各位好好看看吧。。绝对经典,Copy自Msdn
      

  5.   

    DIABL0举的例子是很贴近基本概念的代理,所有的事件代理,事务代理(COM代理),原理都是一样的。很直接的理解就是把代理想成C++中的函数指针。
      

  6.   

    闲来无事,翻译了玩玩,可能有错误,请大家指正这篇文章讲的好像不是很深入Delegates 和 EventsDelegates
    多数情况,对函数的调用是之间的。例如类 MyClass 有一个函数 Process,我们一般会这样调用(台:呼叫:)它:MyClass myClass = new MyClass();
    myClass.Process();这适用于大部分情况(台:状况:)。然而有时我们不会之间调用一个函数,而是把函数传递给一个别的什么,让它去调用这个函数。
    这种能力在event-driven(事件驱动)的系统中非常有用。比如在GUI中,当需要在用户点击一个button后执行一定的代码,或………
    (这里不会翻:)。看看下面的例子:public class MyClass 
    {
    public viod Process()
    {
    Console.WriteLine("Process() begin");
    // other stuff here...
    Console.WriteLine("Process() end");
    }
    }在这个类中,我们在函数开始和结束的时候做了一些logging。问题是,这些logging是固定的“写死”在代码中的,它只能把信息写到
    console。我们需要在函数的外面来控制log信息要存储到哪里去。Delegate适合这样的工作。它可以让我们在看起来没有指定某一个函数的情况下去调用这个特定的函数(有点拗口:)。对delegate的
    声明很象声明函数。所不同的地方是,我们还要指定函数的signature以便delegate能够引用(reference)函数。对于上面的例子,我们声明一个delegate,它接受一个string型参数,没有返回值。把上面的例子改成:public class MyClass
    {
      public delegate void LogHandler(string message);
      public void Process(LogHandler logHandler)
      {
          if (logHandler != null)
            logHandler("Process() begin");
          // other stuff here…
          if (logHandler != null)
            logHandler ("Process() end");
      }
    }除了需要在调用前检查delegate是否为空,使用delegate就和直接调用一个函数没有什么区别。要调用Process()需要声明一个logging函数和delegate配合,然后创建一个这个delegate的实例,并指向logging函数。class Test
    {
      static void Logger(string s)  {
          Console.WriteLine(s);
      }  public static void Main()
      {
          MyClass myClass = new MyClass();      MyClass.LogHandler lh = new MyClass.LogHandler(Logger);
      
          myClass.Process(lh);
      }
    }我们想在Process()函数中调用Logger()函数。在Main()里面创建delegate实例,把Logger函数传给delegate的constructor(构造函数)。
    最后把delegate传递给Process()函数。这样Process()中就会调用Logger()。如果你有使用C++的经验,你可能会认为delegate就是函数指针。delegate确实接近函数指针,不过它不只是一个指针,它还能够提供更
    多的功能。Passing State(传递状态)
    上面的例子实在很简单,Logger()只是把一个string写到console上。考虑一下把log信息写到文件里的情况,这时函数需要知道文件的信息。C#可以引用static或member function。下面是一个引用成员函数的例子:class FileLogger
    {
      FileStream fileStream;
      StreamWriter streamWriter;  public FileLogger(string filename)
      {
          fileStream = new FileStream(filename, FileMode.Create);
          streamWriter = new StreamWriter(fileStream);
      }  public void Logger(string s)
      {
          streamWriter.WriteLine(s);
      }  public void Close()
      {
          streamWriter.Close();
          fileStream.Close();
      }
    }
    class Test
    {
      public static void Main()
      {
          FileLogger fl = new FileLogger("process.log");
          
          MyClass myClass = new MyClass();      MyClass.LogHandler lh = new MyClass.LogHandler(fl.Logger);
      
          myClass.Process(lh);
          fl.Close();
      }
    }FileLogger类封装了存储log信息的文件。在Main()中delegate指向了FileLogger类的Logger()成员函数。这里我们没有改动Process(),你是不是觉得很cool?(译按:一般般啦:)不论delegate是引用static函数或member函数,调用delegate的代码都是一样的。Multicasting
    C#中,delegate是multicast的。multicast就是delegate可以同时指向多个函数。一个multicast delegate维护着一个函数的list。我们可以修改一下上面的例子,
    让Process调用两个delegate。要结合两个delegate应使用Delegate.Combin()函数。代码如下:      MyClass.LogHandler lh = (MyClass.LogHandler) 
            Delegate.Combine(new Delegate[] 
                {new MyClass.LogHandler(Logger),
                new MyClass.LogHandler(fl.Logger)});鉴于上面的写法比较丑,可以用+=来结合两个delegate: MyClass.LogHandler lh = null;
          lh += new MyClass.LogHandler(Logger);
          lh += new MyClass.LogHandler(fl.Logger);要从一个multicast delegate中去掉一个delegate可以用 Delegate.Remove() 或 -=操作符。当调用一个multicast delegate时,会按顺序同步地(?)调用list中的delegate。如果想自己控制调用的顺序,你可以从delegate中获得list,并自行调用函数:foreach (LogHandler logHandler in lh.GetInvocationList())
    {
      try
      {
          logHandler(message);
      }
      catch (Exception e)
      {
          // do something with the exception here…
      }
    }注意这里的try-catch,它可以捕获一个handler的异常,而不影响其他handler的执行,如果try的范围太大,一个handler的异常会导致它后面的handler都没有
    机会执行。
    Events
    Why do we need events, if we have delegates? 让偶来回答这个问题 ;)最好的答案是一个 user interface object中的event。比如一个button可以有一个public的Click delegate。我们可以钩一个函数到这个delegate上面,在着个button
    被点击的时候,调用delegate。象这样: Button.Click = new Button.ClickHandler(ClickFunction);ClickFunction就是要钩上去的函数。Quiz: Is there a problem with the code above? What have we forgotten?我们没有用+=,而是直接把函数指派给了delegate,这样的话,其他已经钩上delegate的函数都被去掉了 ;( 因为Button.Click是公有的,它无法避免这类情况的出现。
    比如Button.Click = hull;  这会把所有的delegate都去掉。只有一个dalegate的情况还没有什么问题,但是当另外一个delegate加上去后就出状况了 ;(Event 在 delegate模型上加了一个保护层,以防这种状况的出现。看看下面的代码:public class MyObject
    {
      public delegate void ClickHandler(object sender, EventArgs e);
      public event ClickHandler Click;  protected void OnClick()
      {
          if (Click != null)
            Click(this, null);
      }
    }ClickHandler 是一个标准的event delegate。名字用handler结尾,接受两个参数。第一个是发送事件的object,第二个用来传送event的信息。上面的例子没有
    什么信息要传递,所以就用EventArgs。如果有信息要传应该使用它的子类,比如MouseEventArgs。Click event的声明做了两件事。一,声明了一个叫Click的delegate成员变量,这个变量是用于类的内部使用的。二,声明了一个叫Click的event用于类的外部。类中一般都包含类似例子中的OnClick()的函数,以便其子类也可以触发event。你可能注意到触发时间的代码类似于调用delegate的代码,这是因为Click就是一个delegate。类似于delegate,我们可以用+=和-=来把函数钩到event上,但是,不同的是,只能用这两种方法操作event。使用event很简单:class Test
    {
      static void ClickFunction(object sender, EventArgs args)
      {
          // process the event here.
      }
      public static void Main()
      {
          MyObject myObject = new MyObject();      myObject.Click += new MyObject.ClickHandler(ClickFunction);      
      }
    }We create a static function or a member function that matches the signature of the delegate, and then add a new instance of the delegate to the event with +=.
      

  7.   

    简单的说delegate是个函数指针,但它能指向多个函数,通过+=、-+操作,准确地说应该是函数指针的链表。