無法將匿名方法轉換為System.Delegate


在WinForm中,不允許非UI線程訪問UI,如果非UI線程需要跨線程調用UI控件,通常的解決辦法是使用Control類中的Invoke方法,傳遞給該方法一個委托和委托調用的參數列表(params []object args),任何委托類型都可以,通過委托來訪問UI。其內部是,非UI線程把委托送到UI線程中,讓UI線程去調用這個委托。

一般一個方法的參數是委托類型,如果使用委托實例,那就還需要額外定義一個和委托簽名一致的方法,比較麻煩。而我一般是使用匿名方法,因為匿名方法方便,不需要額外的聲明的一個委托類型了,讓代碼更加簡潔。但是這一次使用匿名方法卻出現了錯誤,在編譯的時候就沒有被通過,我代碼如下(code1):

 this.Invoke(delegate(string test) {this.Text=test;},"myCall");

編譯時錯誤如下:

無法將 匿名方法 轉換為類型“System.Delegate”,因為它不是委托類型

經過仔細思考,發現這樣的寫法通過編譯確實是對的。首先得明白所有的委托類型都是繼承System.Delegate,而Invoke方法委托類型就是Delegate,也就是說,任意的委托類型都可以作為該方法的參數。如果我們使用匿名方法,那么CLR就不知道把該匿名方法轉為哪種類型的的委托,因此直接傳入一個匿名函數是通不過編譯的。知道了為什么錯誤,代碼改成下面這樣(code2),就能夠正確的運行羅。

Action<string> updateUI = (text) => this.Text = text;
this.Invoke(updateUI,"myCall");
// 或者這樣,和上面一樣,還是傳入Action<string>委托實例
this.Invoke(new Action<string>((text) => this.Text = text), "myCall");

在使用委托類型的時候,建議最好采用系統內部定義Action和Func兩種委托類型,而且這兩種類型還定義了許多個泛型版本,足夠滿足我們平常的應用啦。

那么在哪種情況下可以直接傳入匿名方法作為參數,舉個例子,在使用Linq的擴展Where方法的時候,該方法需要傳入一個委托,委托的定義為Func<T,bool>,這種情況我們可以直接使用一個匿名方法,代碼如下(code3):

list.Where((s) => s.StartsWith("n"));

因此可以知道,當方法的參數是具體的委托類型時,可以使用匿名方法,因為編譯器知道應該把該匿名方法轉為何種委托類型;而 當方法的參數為委托的基類System.Delegate時,那就需要自己實例化一個具體委托類型實例(委托類型使用.NET內部定義的,如code2),然后傳入進去,這樣CLR知道就是何種委托類型。

在C#3.0中有了一個叫Lambda的表達式,和匿名方法是一樣效果,但是Lambda能夠使代碼更加緊湊,更加優異,主要是比較容易理解表達式,可讀性好,關於Lambda的用法在這里就不做介紹了。上面的code2和code3的匿名方法都是采用的Lambda表達式,是不是看起來更加簡潔。


免責聲明!

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



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