2016-04-17 5 views
3

elvis演算子(nu​​llsafe逆参照演算子??)を含む式で拡張メソッドを呼び出すと、結果のnullが期待通りに拡張メソッドに渡されません。本質的に、予期しないヌル参照例外が発生する可能性があります。これを示すプログラムは次のとおりです。エルビス演算子(Nullsave Dereference Operator)がnull参照例外を引き起こしていますか?

class Program 
{ 
    static void Main(string[] args) 
    { 
     string nil = null; 
     foreach (var c in ((nil?.ToCharArray()).EmptyIfDefault())) { }; // works 
     foreach (var c in (nil?.ToCharArray().EmptyIfDefault())) { }; // nullref 
    } 
} 

public static class Utility 
{ 
    public static char[] EmptyIfDefault(this char[] target) 
    { 
     return target ?? new char[0]; 
    } 
} 

この動作が仕様であれば、誰かがありますか?通知はありませんか? ToCharArray()とEmptyIfDefaultの間にあります。もしあれば、私は現在の行動を理解するだろう。今、バグのようです。 (これをマイクロソフトに報告する正しい方法は何ですか?)

同じ動作をする他の人には、余分な中かっこがそれを防止するようです。ところで

(:

それが関連している:ここで私は私は私の質問の中に下記の答えをちょうど含まれます:)

public static IEnumerable<TTarget> EmptyIfNull<TTarget>(this IEnumerable<TTarget> target) 
    { 
     return target ?? Enumerable.Empty<TTarget>(); 
    } 

編集を使用しています実際のEmptyIfNullです共通の落とし穴:これも

として解釈さ

var txt = "I am " + 
    age>=18 ? "mature" : "not old" + 
    " enough."; 

書き換えられたとき

var txt = "I am " + 
    age >= 18 
     ? "mature" 
     : ("not old" + " enough."); 

、括弧なしの行動は理にかなって:それは最初に直感的ですが

foreach(var c in 
    nil == null 
     ? null 
     : nil.ToCharArray().EmptyIfDefault()) { }; // nullref 
+0

「elvis operator」はこれまで聞いたことがありませんでしたが、私はそれが好きです。 – Steve

答えて

5

、それは間違いなくバグではありません。

var t = nil?.ToCharArray().EmptyIfNull(); 

上記の意志ないコール:あなたはのは、この例を見てみましょう

(式を評価しながら、それは例外を投げていない)nullを反復しようとしているので、あなたはNullReferenceExceptionを取得していますがnullとなり、メソッドチェーンが短絡してnullが返されるため、EmptyIfNullが返されます。初期条件に合格した場合(つまり、nilがnullでない)EmptyIfNullのみが実行する

IEnumerable<char> t; 
if (nil != null) 
    t = nil.ToCharArray().EmptyIfNull(); 
else 
    t = null; 

注:ある

は、我々は、上記のように書くことができます。

ここで、角かっこはなぜそれを修正するのですか?

var t = (nil?.ToCharArray()).EmptyIfNull(); 

これは、ように書き換えることができます - その後、私たちは常に結果にコールEmptyIfNull

IEnumerable<char> t; 
IEnumerable<char> temp; 
if (nil != null) 
    temp = nil.ToCharArray(); 
else 
    temp = null; 
t = temp.EmptyIfNull(); 

は短絡行動だけ内側の式に適用されることを参照してください。

+1

ああ、オペレーターの先行と関係があります。 "ドット演算子"(私はそれを単に呼び出します)は、 "null dereferincing operator"を優先します。 var t = nil == null? null:nil.toCharArray()。EmptyIfNull() – realbart