C# 淺談委托----溫故而知新


 

先看看委托的概述:

 

•委托類似於 C++ 函數指針,但它們是類型安全的。

• 委托允許將方法作為參數進行傳遞。

• 委托可用於定義回調方法。

• 委托可以鏈接在一起;例如,可以對一個事件調用多個方法。

•方法不必與委托簽名完全匹配。 有關更多信息,請參見 在委托中使用變體(C# 和 Visual Basic)。

• C# 2.0 版引入了匿名方法的 概念,此類方法允許將代碼塊作為參數傳遞,以代替單獨定義的方法。 C# 3.0 引入了 Lambda 表達式,利用它們可以更簡練地編寫內聯代碼塊。 匿名方法和 Lambda 表達式(在某些上下文中)都可編譯為委托類型。 這些功能統稱為匿名函數。 有關 lambda 表達式的更多信息,請參見 匿名函數(C# 編程指南)。

 

委托是一種定義方法簽名的類型。 當實例化委托時,您可以將其實例與任何具有兼容簽名的方法相關聯。 您可以通過委托實例調用方法。

 

委托用於將方法作為參數傳遞給其他方法。 事件處理程序就是通過委托調用的方法。 您可以創建一個自定義方法,當發生特定事件時某個類(例如 Windows 控件)就可以調用您的方法。 

 

例子1:

    class Program
    {

        static void Main(string[] args)
        {
            Hello();
        }

        static void Hello()
        {
            System.Console.WriteLine("Hello, Delegate!");
        }
    }

這是一個常見的方法, 輸出一段字符串Hello, Delegate!

下面我們來把他寫成委托,

    class Program
    {
        delegate void PrintHello();

        static void Main(string[] args)
        {
            PrintHello ph = new PrintHello(Hello);
            ph.Invoke();
        }

        static void Hello()
        {
            System.Console.WriteLine("Hello, Delegate!");
        }
    }

這里的PrintHello的方法類型需要和Hello保持一直,另外參數也需要保持一致,現在是無參數的.講Hello作為參數傳到委托中,然后用Invoke調用.
以上代碼也會輸出,Hello, Delegate!因為invoke了這個方法.

 

從.net 2.0開始就使用匿名委托, 可以這樣申明

delegate { };

或者帶參數的

delegate (string i){ };

{}括號中可以寫需要執行的邏輯代碼.

有了匿名委托我們就可以偷一下懶了,可以把上面的例子改成如下:

    class Program
    {
        delegate void PrintHello();

        static void Main(string[] args)
        {
            PrintHello ph = delegate 
            { 
                System.Console.WriteLine("Hello, Delegate!"); 
            };
            ph.Invoke();

        }

        //static void Hello()
        //{
        //    System.Console.WriteLine("Hello, Delegate!");
        //}
    }


在.net 3.0中新加了Action<T> 無返回的委托, Predicate<T>有返回值,且返回true或false的委托.

我們可以將上面的例子改成有參數的,

    class Program
    {
        static Action<string> print = delegate(string i) { System.Console.WriteLine("Hello, {0}!",i); };

        static void Main(string[] args)
        {
            print.Invoke("Delegate");
        }
    }

或者用lambda表達式替代匿名委托,進一步偷懶..

    class Program
    {
        static Action<string> print = (i)=>{ System.Console.WriteLine("Hello, {0}!",i); };

        static void Main(string[] args)
        {
            print.Invoke("Delegate");
        }
    }

以上會輸出Hello,Delegate!因為將Delegate傳入到最后輸出.

再來講解一下Predicate這個只返回true or false的委托,如下:

    class Program
    {
        static Predicate<string> print = (i) => { return string.IsNullOrEmpty(i); };
        
        static void Main(string[] args)
        {
            System.Console.WriteLine(print.Invoke("Hello, Delegate!"));
        }
    }

以上代碼會輸入true因為i不是為null or empty.

 

在.net 3.5中又新加了Action(無返回值的委托,類似於delegate void)和Func<T,T> 帶返回參數的,參數類型是T,返回類型也可以是int,string等..

所以剛才的無參數的例子又可以寫成這樣:

    class Program
    {
        static Action print = () => { System.Console.WriteLine("Hello, Delegate!"); };

        static void Main(string[] args)
        {
            print.Invoke();
        }
    }


再來看看Func<T,TReslut> 第一個T代表參數的類型,第一個TReslut代表返回結果的類型。

如下,參數的類型是int,返回的類型是string.

    class Program
    {
        static Func<int,string> print = (i) => { return "Hello, Delegate!"+i.ToString(); };
        
        static void Main(string[] args)
        {
            System.Console.WriteLine(print.Invoke(0));
        }
    }

輸出的結果是:Hello, Delegate!0

 

再來看看委托的回調函數,如下:

    class Program
    {
        delegate string callback(string firstName, string lastName);

        static void Main(string[] argss)
        {
            DoCallback("Charlie", "Wang", en_US);
            DoCallback("Tom", "Chen", ch_ZN);

        }

        static void DoCallback(string firstName, string lastName, callback call)
        {
            string result=call(firstName, lastName);
            Console.WriteLine(result);
        }

        static string en_US(string firstName, string lastName)
        {
            return firstName + " ," + lastName;
        }

        static string ch_ZN(string firstName, string lastName)
        {
            return lastName+", "+firstName;
        }
    }

輸出的結果為:

Charlie ,Wang
Chen, Tom

我們還可以將以上代碼進一步精簡,用Func代替.

    class Program
    {
        static void Main(string[] argss)
        {
            DoCallback("Charlie", "Wang", en_US);
            DoCallback("Tom", "Chen", ch_ZN);

        }

        static void DoCallback(string firstName, string lastName, Func<string,string,string> callback)
        {
            string result = callback(firstName, lastName);
            Console.WriteLine(result);
        }

        static string en_US(string firstName, string lastName)
        {
            return firstName + " ," + lastName;
        }

        static string ch_ZN(string firstName, string lastName)
        {
            return lastName+", "+firstName;
        }
    }

我們還可以這樣寫.

    class Program
    {
        static void Main(string[] argss)
        {
            DoCallback("Charlie", "Wang", en_US);
            DoCallback("Tom", "Chen", ch_ZN);
            DoCallback("Kevin", "Liu", (lastName, firstName) => { return string.Format("This is {0} {1}", lastName, firstName);});
        }

        static void DoCallback(string firstName, string lastName, Func<string,string,string> callback)
        {
            string result = callback(firstName, lastName);
            Console.WriteLine(result);
        }

        static string en_US(string firstName, string lastName)
        {
            return firstName + " ," + lastName;
        }

        static string ch_ZN(string firstName, string lastName)
        {
            return lastName+", "+firstName;
        }
    }

輸出結果為:

Charlie ,Wang
Chen, Tom
This is Kevin Liu

 

委托在很多時候使用可以精簡我們的代碼,看起來比較直觀,下面是個很經典的案例:

    class Program
    {
        static void Main(string[] args)
        {
            B b = new B();
        }
    }
    class A
    {
        public A()
        {
            Print();
        }
        public virtual void Print() { }
    }

    class B : A
    {
        int x = 1;
        int y;

        public B()
        {
            y = -1;
        }
        public override void Print()
        {
            System.Console.WriteLine("x={0},y={1}", x, y);
        }
    }

各位讀者看看以上代碼輸出什么?

    class Program
    {
        static void Main(string[] args)
        {
            B b = new B();
            b.print();
        }
    }
    class A
    {
        public A()
        {
            Print();
        }
        public virtual void Print() { }
    }

    class B : A
    {
        int x = 1;
        int y;
        public Action print = delegate { };

        public B()
        {
            y = -1;
            this.print = Print;
        }
        public override void Print()
        {
            System.Console.WriteLine("x={0},y={1}", x, y);
        }
    }

 

然后再看看以上代碼又輸出什么?



 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM