web-dev-qa-db-ja.com

C#では、nullオブジェクトで拡張メソッドを呼び出すとどうなりますか?

メソッドはnull値で呼び出されますか、null参照例外を与えますか?

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

この場合、「this」パラメーターでnullをチェックする必要はありませんか?

302
tpower

それは問題なく動作します(例外はありません)。拡張メソッドは仮想呼び出しを使用しない(つまり、「callvirt」ではなく「call」il命令を使用する)ので、拡張メソッドで自分で記述しない限り、nullチェックはありません。これは実際にはいくつかの場合に便利です。

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)) {...}

明らかにnullチェックはありません。

361
Marc Gravell

Marc Gravellからの正解への追加。

This引数がnullであることが明らかな場合は、コンパイラから警告を受け取る可能性があります。

default(string).MyExtension();

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

48

既に発見したように、拡張メソッドは単純に栄光を与えられた静的メソッドであるため、null参照が渡され、NullReferenceExceptionがスローされることなく呼び出されます。ただし、呼び出し元にとってはインスタンスメソッドのように見えるため、 振る舞う など。その後、ほとんどの場合、thisパラメーターを確認し、nullの場合は例外をスローする必要があります。以下の例のように、メソッドが明示的にnull値を処理し、その名前が適切に示している場合、これを行わなくてもかまいません。

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; 
  } 
}

私は ブログ投稿 についても少し前に書きました。

20
Jordão

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

メソッドがチェックせずにオブジェクトにアクセスしようとした場合、それがnullである場合、はい、例外をスローします。

ここで、ある人が「IsNull」および「IsNotNull」の拡張メソッドを書いて、参照がnullかどうかをチェックします。個人的には、これは異常であり、日の目を見るべきではなかったと思いますが、完全に有効なc#です。

16
Binary Worrier

他の人が指摘したように、null参照で拡張メソッドを呼び出すと、this引数がnullになり、特別なことは何も起こりません。これにより、拡張メソッドを使用してガード句を作成するというアイデアが生まれます。

例については、この記事を読むことができます: 循環的複雑さを軽減する方法:Guard Clause 短いバージョンはこれです:

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参照で呼び出すことができる文字列クラス拡張メソッドです。

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

呼び出しが正常に機能するのは、ランタイムがnull参照で拡張メソッドを正常に呼び出すためだけです。次に、この拡張メソッドを使用して、面倒な構文なしでガード句を実装できます。

    public IRegisteredUser RegisterUser(string userName, string referrerName)
    {

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

        ...

    }
6
Zoran Horvat

Extensionmethodは静的であるため、このMyObjectに対して何もしなくても問題ないはずです。簡単なテストで検証してください:)

3
Fredrik Leijon