2009-05-11 1 views
241

メソッドがnull値で呼び出されるか、またはnull参照例外が返されますか?C#では、nullオブジェクトの拡張メソッドを呼び出すとどうなりますか?

MyObject myObject = null; 
myObject.MyExtensionMethod(); // <-- is this a null reference exception? 

これが当てはまる場合は、nullのために 'this'パラメータを確認する必要はありませんか?

+37

それはこれらの事を議論するために痛いことはありません。 – tpower

+18

うれしいことはここにあります、時間を節約しました。 – famousgarkin

+6

ご質問ありがとうございます。このサイトのコメントのいくつかは、議論することが決して痛いとtpowerが言っているように、あまりにも負になりつつあります。 – nixon

答えて

304

これは問題なく動作します。拡張メソッドは仮想呼び出しを使用しません(つまり、 "callvirt"ではなく "call" il命令を使用します)。したがって、拡張メソッドで自分で記述しない限り、ヌルチェックはありません。これは、いくつかのケースでは、実際に有用である:

public static bool IsNullOrEmpty(this string value) 
{ 
    return string.IsNullOrEmpty(value); 
} 
public static void ThrowIfNull<T>(this T obj, string parameterName) 
     where T : class 
{ 
    if(obj == null) throw new ArgumentNullException(parameterName); 
} 

など

基本的には、静的呼び出しに呼び出し、非常に文字通りある - すなわち

string s = ... 
if(s.IsNullOrEmpty()) {...} 

次のようになります。

string s = ... 
if(YourExtensionClass.IsNullOrEmpty(s)) {...} 

あり明らかにヌルチェックではありません。

+1

+1、私の答えに追加のメモ。 –

+1

Marc、 "仮想"コールについて話していますが、インスタンスメソッドでの非仮想コールでも同様です。私はここで "仮想"という言葉が間違っていると思います。 –

+2

@Konrad:それは文脈によって異なります。 C#コンパイラは、通常、非仮想メソッドに対しても、正確にnullチェックを取得するためにcallvirtを使用します。 –

2

extensionmethodは静的なので、あなたはそれが問題になることはありませんMyObjectにこれに何もない場合は、簡単なテストでは、それを確認する必要があります:)

12

ヌルが拡張メソッドに渡されます。

このメソッドがnullをチェックせずにオブジェクトにアクセスしようとすると、例外がスローされます。

ここで男は "IsNull"と "IsNotNull"という拡張メソッドを書いています。個人的には、これは収差だと思うし、日光を見てはならないはずですが、それは完全に有効なC#です。

+0

私はあなたに同意する、これは混乱につながる可能性があります。 – Trap

+13

確かに、私には死体に「あなたは生きていますか?」と聞き、「いいえ」の答えを得るのが好きです。死体はどんな質問にも反応することができず、ヌルオブジェクトのメソッドを「呼び出す」こともできません。 –

+2

haha​​!良い例え! :) – Trap

45

Marc Gravellから正解に追加されました。

この引数がnullであることは明らかである場合は、コンパイラから警告を受ける可能性は:

default(string).MyExtension(); 

はよく、実行時に機能しますが、警告"Expression will always cause a System.NullReferenceException, because the default value of string is null"を生成します。

+20

なぜ「常にSystem.NullReferenceExceptionを引き起こす」と警告するのでしょうか?実際、それは決してできませんか? – tpower

+13

検証済み - 面白いコンパイラグリッチ;-p +1工夫のため –

+2

@tpower:このチェックは、拡張メソッドを正しく処理するように更新されていないためです。私は実際に引数の型だけを必要とする拡張メソッドを呼び出そうとしたときにそれを見つけましたが、インスタンスはありませんでした。今私ははるかに長い静的メソッドを呼び出さなければなりません。 –

-1

読解可能で縦向きにするには、いくつかのゴールデンルールがあります。

  • エッフェルからいくつかの前提条件を満たしたと予想される出力あなたのケース に
を保証している場合、いくつかの入力の防止に取り組むべきである方法の中にカプセル化された固有のコードは、そのコードが実行可能であると言いますと言って価値が1 - DesignByContractが壊れています...あなたはnullインスタンスに対していくつかのロジックを実行しようとしています。

+0

Bertrand Meyerのそんなスマートな男 – Trap

12

既に発見したように、拡張メソッドは単純に栄光の静的メソッドであるため、null参照が渡され、NullReferenceExceptionがスローされることなく呼び出されます。しかし、呼び出し元にインスタンスメソッドのように見えるので、と同様に動作する必要があります。ほとんどの場合、thisパラメータをチェックし、nullの場合は例外をスローする必要があります。私もいくつかの時間前にこのことについてa blog postを書いた

public static class StringNullExtensions { 
    public static bool IsNullOrEmpty(this string s) { 
    return string.IsNullOrEmpty(s); 
    } 
    public static bool IsNullOrBlank(this string s) { 
    return s == null || s.Trim().Length == 0; 
    } 
} 

:この方法は、明示的にnull値の世話をし、その名前は以下の例のように、正式にそれを示している場合、これを行うにはないOKです。

4

他の人が指摘しているように、null参照で拡張メソッドを呼び出すと、この引数はnullになり、特別なことは起こりません。これにより、拡張メソッドを使用してガード句を記述するという考え方が生まれます。

あなたは例のために、この記事を読むことができる:

((string)null).AssertNonEmpty("null"); 

コール作品:

public static class StringExtensions 
{ 
    public static void AssertNonEmpty(this string value, string paramName) 
    { 
     if (string.IsNullOrEmpty(value)) 
      throw new ArgumentException("Value must be a non-empty string.", paramName); 
    } 
} 

これはnull参照で呼び出すことができます文字列クラスの拡張メソッドです:How to Reduce Cyclomatic Complexity: Guard Clauseショートバージョンはこれですランタイムはヌル参照で拡張メソッドを正常に呼び出すためにのみ有効です。そして、あなたは厄介な構文なしガード条項を実施するために、この拡張メソッドを使用することができます。

public IRegisteredUser RegisterUser(string userName, string referrerName) 
    { 

     userName.AssertNonEmpty("userName"); 
     referrerName.AssertNonEmpty("referrerName"); 

     ... 

    } 
関連する問題