2016-01-20 40 views
4

這是關於C#的新引入的空值檢查運算符的問題。運營商'?'不能應用於類型'方法組'的操作數

假設我有這樣一個接口:

interface ILogger 
{ 
    void Log(string message); 
} 

,並期望一個功能的記錄行動:

void DoWork(Action<string> logAction) 
{ 
    // Do work and use @logAction 
} 

爲什麼我得到下面的編譯錯誤,如果我嘗試寫:

void Main(string[] args) 
{ 
    ILogger logger = GetLogger(); // Assume GetLogger() may return null 

    // 
    // Compiler error: 
    // Operator '?' cannot be applied to operand of type 'method group' 
    // 
    DoWork(logger?.Log); 
} 
+0

http://stackoverflow.com/questions/32580536/operator-cannot-be-applied-to-operand-of-type-t的可能重複 –

+0

你可以顯示'GetLogger()'嗎?你的'DoWork()'似乎與你面臨的問題無關。 – krillgar

+0

當'logger'爲空時,您會期待哪種行爲?使'logAction'值爲空?使'logAction'忽略傳遞的字符串(實際上,使其成爲=> {}')?不要叫'DoWork(..)'? –

回答

13

這裏沒有什麼特別的事情與?.在這裏,它的工作原理就像它用?:logger?.Log會得到與logger == null ? null : logger.Log相同的結果,只有logger只被評估一次。

問題是logger == null ? null : logger.Log在早期版本的C#中一樣無效。 ?:要求一個操作數可以轉換爲另一個操作數的類型,但nulllogger.Log都沒有類型。你必須把它寫成例如logger == null ? null : (Action<string>) logger.Log

不幸的是,引入該鑄造意味着沒有,你可以使用簡單漂亮的C#6縮短版本,同樣也適用於?.logger?.Log是無效的,因爲logger.Log沒有一個類型,所以logger?.Log沒有一個類型不過,如果它是一個沒有類型的表達式,並且它不是一個方法組,那麼C#就沒有任何東西可以處理它。

+0

1.這是否意味着?對三元運算符來說,語法糖或多或少是有效的? 2.你有一個想法,爲什麼logger.Log沒有類型?編譯器似乎有足夠的線索來說明它的類型。 –

+0

@ AhmedA.Hamid 1.只記錄一次「記錄器」的事實對我來說意味着把它稱爲句法糖是不公平的,但如果你不同意,我不會爭辯。 2.方法組從不具有類型。它不能是'Action ':給定'public delegate void MyStringAction(string s);',類型'MyStringAction'將是一個同樣可以接受的委託類型的例子。 C#編譯器無需選擇上下文就可以選擇,但是一個語言設計決策已經使得C#不需要尋找太多的上下文。 – hvd

+0

我同意你的意見嗎?不僅僅是語法糖。這只是你的回答給我的印象是在空檢查操作員和三元操作員之間存在某種轉換或連接。有沒有? 再次感謝。 –

-1

添加到@hvd聲明

我們也可以使用空條件運算符(?)空-合併運算符(?) 如果你寫下面的代碼

string userName = null; 
int len = userName.Length; 

那麼

userName.Length 

會拋出異常:「unhandl在ConsoleApplication中發生了'System.NullReferenceException'類型的異常... 附加信息:未將對象引用設置爲對象的實例。

,如果你使用下面的代碼

string userName = null; 
int? len = userName.Length; 

你仍然會得到相同的異常

int? len = userName?.Length; 

它會返回null,不會拋出異常

但我們仍然有一個問題。問題是我使用int? (Nullable int),這是不好的,因爲人們會更喜歡如果string爲null,那麼它應該返回0.

所以我們可以通過組合null條件運算符(?.)和null-合併運算符(? ?)

int len = userName?.Length ?? 0; 

新增

我們有空條件運算符的另一個用途了。

,當你與事件在這種情況下處理工作,我們可以使用

myCustomEventHandler .Invoke(這一點,EventArgs.Empty)是怎樣的?;

其中「myCustomEventHandler」是C#6.0之前的公共事件,我們必須創建「myCustomEventHandler」的本地副本,否則在多線程應用程序中可能會引發異常。而在C#6中,我們可以直接調用「myCustomEventHandler」而不創建本地副本,並且它是線程安全的。

例如在C#C#5

var handler= this.myCustomEventHandler; 
if (handler!= null) 
    handler(…) 
myCustomEventHandler?.Invoke(e) 
+0

我不太確定這個說法:「因爲人們會更喜歡如果string爲null,那麼它應該返回0」。這不是多麼可行的工作;使用空檢查運算符的默認值是這樣的,你可以得到null或value。 –

+0

@ AhmedA.Hamid,我提供了一個例子,它也可以用這種方式。 我們還有另一個空條件運算符的用法。就像你在處理事件處理時一樣,我們可以使用 myCustomEventHandler?.Invoke(this,EventArgs.Empty); 其中「myCustomEventHandler」是公開事件 在C#6.0之前,我們必須創建「myCustomEventHandler」的本地副本,否則它可能在多線程應用程序的情況下引發異常。而在C#6中,我們可以直接調用「myCustomEventHandler」而不創建本地副本,並且它是線程安全的。 –

0

如果你能你的界面更改爲

interface ILogger 
{ 
    //void Log(string message); 
    Action<string> Log {get; } 
} 

然後你可以使用logger?.Log符號。

的ILogger實現將然後看起來像

class Logger : ILogger 
{ 
    Action<string> Log => str => { /* Do stuff with str */ }; 
} 
相關問題