zoukankan      html  css  js  c++  java
  • Explaining Delegates in C#

    I hear a lot of confusion around Delegates in C#, and today I am going to give it shot of explaining the stuff with easy to understand examples. First things first... I will consciously try NOT to use any technical jargon to explain this concept.

    So here we go, without giving any technical explanation, let's start with a console application...

    // Declaration
    public delegate void VerySimpleDelegate();
    
    class TestDelegate
    {
        public static void Foo()
        {
            Console.WriteLine("Foo was called by a delegate!");
        }
    
        public static void Bar()
        {
            Console.WriteLine("Bar was called by a delegate!");
        }
    
        public static void Main()
        {
            // Instantiation
            VerySimpleDelegate vsd = new VerySimpleDelegate(Foo);  //#1
    
            // Invocation
            vsd();
    
            //Another Instantiation
            vsd = Bar;
            vsd();
        }
    }

    What do you notice when you run the application? Yes, you are right... you are not calling the functions Foo and Bar directly! Instead, you are creating a delegate (#1). Also notice, you just assigned vsd = Bar, which was another function name. Calling vsd again in the next line called the function called Bar as you can see in the output below!!!

    Thus, to use delegate you need to use the following approach... (check the comments in code snipped above to find the following)

        Declaration
        Instantiation
        Invocation

    May be you are thinking, why all this headache? What is the need to do all this?

    Reason 1> You have to call different functions based on some dynamic requirement but you don't want your function calls to change. In our previous code snipped vsd() doesn't change, although the actual function that it is referring to has changed altogether.

    Let's take a look at another sample... Example2

    public class Example2
    {
        // Declaration - Take 1 parameter, return nothing
        public delegate void LogHandler(string message);
    
        // Instantiation - Create a function which takes delegate as one parameter
        // Verify if it is null before you use it
        public void Process(LogHandler logHandler)
        {
            if (logHandler != null)
            {
                logHandler("Process() begin");
            }
    
            if (logHandler != null)
            {
                logHandler("Process() end");
            }
        }
    }
    
    public class Example2DelegateConsumer
    {
        // Create a method with the same signature as the delegate
        static void Logger(string s)
        {
            Console.WriteLine(s);
        }
    
        public static void Main(string[] args)
        {
            Example2 ex2 = new Example2();
    
            // Invocation in the client
            Example2.LogHandler myLogger = new Example2.LogHandler(Logger);
            ex2.Process(myLogger);
        }
    }

    Reason 2> As you can see above, you can use delegates to call static functions. In our case, the function Logger with a parameter was being called by Process function in the Example2 class. This approach is called Callback.

     public class Example3
        {
            // Declaration - Take 1 parameter, return nothing
            public delegate void LogHandler(string message);
    
            // Instantiation - Create a function which takes delegate as one parameter
            // Verify if it is null before you use it
            public void Process(LogHandler logHandler)
            {
                if (logHandler != null)
                {
                    logHandler("Process() begin");
                }
    
                if (logHandler != null)
                {
                    logHandler("Process() end");
                }
            }
        }
    
        public class FileLogger
        {
            FileStream fs;
            StreamWriter sw;
    
            // Constructor
            public FileLogger(string filename)
            {
                fs = new FileStream(filename, FileMode.Create);
                sw = new StreamWriter(fs);
            }
    
            // Create a method with the same signature as the delegate
            public void Logger(string s)
            {
                sw.WriteLine(s);
            }
    
            public void Close()
            {
                sw.Close();
                fs.Close();
            }
        }
    
        public class Example3DelegateConsumer
        {
            static void Main(string[] args)
            {
                FileLogger fl = new FileLogger("C:\Labfiles\process.log");
                Example3 ex3 = new Example3();
                
                // Invocation in the client
                // Notice that now instead of Logger function, we are passing fl.Logger function.
                Example3.LogHandler myLogger = new Example3.LogHandler(fl.Logger);
                ex3.Process(myLogger);
                fl.Close();
            }
        }

    Reason 3> Without changing the Example3 delegate, we were able to change the location where a log needs to be written. In the previous example, you would have noticed that we had a Logger function in the same class. Now, we know we can point to any function with the same signature as a delegate from a different class as well. In our example we called the function from the class FileLogger. The key here is that the Logger function is not in the Example3DelegateConsumer class!!!

    What if you want to display the results, and write them at the same time??

    namespace Delegates4
    {
        public class Example4
        {
            // Declaration - Take 1 parameter, return nothing
            public delegate void LogHandler(string message);
    
            // Instantiation - Create a function which takes delegate as one parameter
            // Verify if it is null before you use it
            public void Process(LogHandler logHandler)
            {
                if (logHandler != null)
                {
                    logHandler("Process() begin");
                }
    
                if (logHandler != null)
                {
                    logHandler("Process() end");
                }
            }
        }
    
        public class FileLogger
        {
            FileStream fs;
            StreamWriter sw;
    
            // Constructor
            public FileLogger(string filename)
            {
                fs = new FileStream(filename, FileMode.Create);
                sw = new StreamWriter(fs);
            }
    
            // Create a method with the same signature as the delegate
            public void Logger(string s)
            {
                sw.WriteLine(s);
            }
    
            public void Close()
            {
                sw.Close();
                fs.Close();
            }
        }
    
        public class Example4DelegateConsumer
        {
            // Create a method with the same signature as the delegate
            static void Logger(string s)
            {
                Console.WriteLine(s);
            }
            
            static void Main(string[] args)
            {
                FileLogger fl = new FileLogger("C:\Labfiles\process.log");
                Example4 ex4 = new Example4();
    
                // Invocation in the client
                // Notice that now instead of Logger function, we are passing fl.Logger function
                // along with another Logger which is defined in the same class
                Example4.LogHandler myLogger = null;
                myLogger += new Example4.LogHandler(Logger);
                myLogger += new Example4.LogHandler(fl.Logger);
                ex4.Process(myLogger);
                fl.Close();
            }
        }
    }

    Reason 4> As you can see above, we have registered two methods for the same delegate. This is what is typically mentioned as Multicast delegate.  By default in C#, delegates are multicast.

    I hope this clarifies the basic concepts of delegates, and why you would use them in the first place. In the next post, I will tell you about how to use delegates for events.  

    转: http://www.dotnetscraps.com/dotnetscraps/post/explaining-delegates-in-c.aspx

  • 相关阅读:
    《数据挖掘系统支撑下的高考志愿填报在线咨询系统设计与实现》论文笔记(十二)
    《基于本体的高考志愿填报辅助系统的设计与实现》论文笔记(十一)
    20189312任方园《网络攻防》第十次作业
    20189312任方园《网络攻防》第九次作业
    20189312任方园《网络攻防》第八次作业
    20189312任方园《网络攻防》第七次作业
    20189312任方园《网络攻防》第六次作业
    20189312任方园《网络攻防》第五次作业
    20189312任方园《网络攻防》第四次作业
    20189312任方园《网络攻防》第三次作业
  • 原文地址:https://www.cnblogs.com/shuaixf/p/3319111.html
Copyright © 2011-2022 走看看