关于C#事件和委托(Regarding Events and Delegates in C#)

2019-10-29 20:13发布

什么是考虑到事件的委托类型实例的副作用?

乔恩斯基特说,“事件不会委派的情况。” 在这里。 我不会问,如果我读了这个其他地方。

我一直,在过去的2个月,可视事件与事件关键字只是在防止委托的无效通过事件被调用帮助特殊类型的委托。

可能有人请详细说明如何正确可视化的整体概念的人新的C#和基于事件的编程?

编辑1:

我的理解代表的概念,因此事件被证明是一个非常简单的概念。 我想继续和我的战斗有这些构建过程中添加由我唤出一个例子。 我加入了很多的意见更好地理解。 这意味着新的球员像我这样的:

图书馆DLL:

namespace DoSomethingLibrary
{
    /*
     *This is a public delegate declared at the base namespace level for global presence.
     *The question is WHY do we need to have a DELEGATE here?
     *The answer is: I do not want to implement the LOGGING logic. Why? Well, my consumers are many
     *and all are equally demanding. They all need different types of logging. Some need HTML logging, 
     *some need XML logging for their custom log analyzer, some need plain text logging etc...
     *This is hell for me. How am I going to support all their demands. I cannot. Thus, I ask them to 
     *implement LOGGING on their side. I am providing an INTERFACE(literal sense) in the guise of a DELEGATE.
     *A DELEGATE is a HOOK.
     *This is the hook that is needed for consumers to hook their custom loggers into the library.
     */
    public delegate void Logger(string firstParam, string secondParam);

    public class PrintingManiac
    {
        public Logger printingManiacConsumerLoggerHook;
        public void StartPrintingLikeAManiac()
        {
            for (int iterator = 0; iterator <= 3; iterator++)
            {
                /*This loop is an emulator which I am using to emulate some huge processing or some huge job.
                 *Let us imagine that this is a library that does some heavy data crunching OR some 
                 *extremely complex data access job etc..
                 */
                Console.WriteLine("Actual WORK - " + iterator.ToString());
                /*After each step this library tries to LOG. But NOTE that this library
                 *has no LOGGER implemented. Instead, this library has judiciously DELEGATED
                 *the logging responsibilty to the CONSUMER of this library.
                 */
                printingManiacConsumerLoggerHook("Actual Work", "Step " + iterator.ToString());
            }
        }
    }
}

对消费可执行文件:

/*
 * Let us assume that I have purchased the DoSomethingLibrary DLL from a vendor.
 * I have to add the DLL as a reference to my executable's project in Visual Studio.
 * I also have to use the DoSomethingLibrary namespace to access the Logic in the DLL.
 */
using DoSomethingLibrary;

namespace UnderstandingDelegates
{
    class Program
    {
        static void Main(string[] args)
        {
            /*
             * Creating an object of the lone class PrintingManiac in the DoSomethingLibrary
             */
            PrintingManiac newManiac = new PrintingManiac();

            /*
             * HOOKING my custom logger to the DoSomethingLibrary DLL.
             * I get the best of both the worlds. I have a well-tested and efficient library working for me
             * AND I have the best logging avaliable.
             * The DoSomethingLibrary DLL has no knowledge of what logging this executable is going to use.
             * This executable has to just satisfy the requirements of the DELEGATE signature of DoSomethingLibrary DLL.
             */
            newManiac.printingManiacConsumerLoggerHook += new Logger(ClientsCustomizedLoggerTwo);

            newManiac.StartPrintingLikeAManiac();
            Console.ReadLine();
        }

        public static void ClientsCustomizedLoggerOne(string firstParam, string secondParam)
        {
            /*
             *This logger has '=' used as a decorator
             *In real scenarios the logger may be very complex.
             *Let us assume this is an HTML logger
             */
            Console.WriteLine("=============================");
            Console.WriteLine("Delegated Logging IN CONSUMER code " + firstParam + " - " + secondParam);
            Console.WriteLine("=============================");
        }

        public static void ClientsCustomizedLoggerTwo(string firstParam, string secondParam)
        {
            /*
             *This logger has '-' used as a decorator
             *Let us assume this is an XML logger
             */
            Console.WriteLine("------------------------------");
            Console.WriteLine("Delegated Logging IN CONSUMER code " + firstParam + " - " + secondParam);
            Console.WriteLine("------------------------------");
        }
    }
}

编辑2:

我已经写了一个在CodeProject上的文章解释清楚代表的整个概念。

Answer 1:

如何正确可视化的整体概念

从来没有人有很大的麻烦C#可视化性能 。 一个属性是一个存取到一个字段 ,它可以防止其他代码从直接操纵字段值。 这样的代码将被强制调用getset访问接入领域。 你可以把任意代码的访问方法,抛出一个异常,当你不开心与传递到设置例如,非常普遍的价值。 该属性的底层存储不必是一个字段或者,可以暴露另一个类对象例如的字段或属性。 等等。

可视化事件的一个好办法就是把它比作一个属性。 具有完全相同的意图,它可以防止其他代码直接操纵委托对象。 他们不得不通过添加移除访问器。 这些方法的调用由在客户端代码的语法糖产生中, +=操作者的呼叫添加(), -=调用删除()。 相媲美的语法糖访问属性,你没有明确写调用get或set方法要么。

是什么样的事件,混乱,使他们显得如此不同的属性是该事件的访问方法是可选的 。 如果你不写他们,那么C#编译器会自动生成它们。 包括后备存储器,一个委托对象。 属性也可以自动生成的访问和备份存储,自动属性做。 但是,语法是不同的,你还是要申报。

使用自动生成的访问是常见的。 该代码几乎总是不够好,它已经提供了任意代码不能删除的其他代码的事件订阅的保证。 没有那么多好的理由写你自己的。 一是削减你的类对象的大小,如果你支持很多事件。 而不是每个单项委托对象,你可以将它们存储在一个EventHandlerList代替。 很常见的,例如.NET框架代码。 额外的间接也在WPF的附加活动和WinRT的与不基于委托的事件模型冤大头。



Answer 2:

事件由两个特殊的方法,称为存取,即addremove 。 两者取一个值参数value相同的委托类型,并返回void

例如,这是一个事件:

public event Action Exploded
{
  add
  {
    Console.WriteLine("Hello from 'add'. Type of 'value' is '{0}'.", value);
  }
  remove
  {
    Console.WriteLine("Hello from 'remove'. Type of 'value' is '{0}'.", value);
  }
}

A“字段样”事件是一个编译器生成的事件的类型,其中有问题的代表类型的私有生成支持字段,并且其中所述add存取增加value到该后备字段(委托组合)的调用列表而在remove访问删除value从该列表。 这是一个聪明的线程安全的方式来完成。



Answer 3:

我觉得困惑的关于C#事件的最大来源之一来自不指定明确的添加和删除方法事件的声明创建具有相同名称的事件(一个设计,我不喜欢,顺便说一句委托的事实梗; VB。 NET在默认情况下使代表一个不同的名称)。 因此,宣称事件foo实际上都宣称事件命名foo和委托名为foo ; 名foo有时指委托,有时返回到事件。

在.net中的事件实在是没有什么比一对的方法,每个接受委托更多。 其中一种方法称为“添加”,并应使该方法以使得如果当/每当一些特定的条件产生/要调用的提供委托。 另一种方法是所谓的“删除”,而应该问的是,“订阅”与特定委托关联被取消。 注意关于一般情况下的合同没有什么要求的事件做一个传入的委托任何东西。 不可变集合可以实现一个“观察集合”的接口,但简单地忽略任何请求添加或删除更改通知[可观察收集的合同将要求所有代表添加到“收藏变”事件被称为当收集的变化,但由于会有任何情况下,其中收集能真正改变,就不会有任何情况下,哪里会需要调用传入的代表。

默认情况下,当一个类一个声明事件eventName在C#中,编译器还声明一个变量eventName与事件的委托类型相关联的。 形式的任何声明eventName += someDelegate将得到翻译为eventName_add(someDelegate)和形式的陈述eventName -= someDelegate将得到翻译为eventName_remove(someDelegate) 所有其他参考eventName ,将被视为该名代表引用。 请注意,在旧版本的C#,如果委托在范围上,的语句+=-=的形式将直接委托,而不是对事件进行操作。 这意味着,虽然从外面一类会去通过添加/删除方法(它将使用锁定或联锁方法来提供线程安全)接受预订请求,这些类中的处理不会是线程安全的。 C#的版本都会把eventName += someDelegateeventName -= someDelegate的添加/删除请求,然而,即使委托是在范围内。



文章来源: Regarding Events and Delegates in C#