C#/。NETでパラメーターをnull不可としてマークしますか?


98

nullC#/。NETで渡されないようにする関数パラメーターに割り当てることができる単純な属性またはデータコントラクトはありますか?理想的には、これはコンパイル時にもチェックして、リテラルnullがどこでも使用されていないことを確認し、実行時にスローしArgumentNullExceptionます。

現在、私は次のようなものを書いています...

if (null == arg)
  throw new ArgumentNullException("arg");

...私がそうではないと予想するすべての議論についてnull

同じメモでNullable<>、以下が失敗するという反対があります:

NonNullable<string> s = null; // throw some kind of exception

7
C#の最近のバージョンでは、 "nameof()"の使用がより効果的です。新しいArgumentNullException(nameof(arg)); そのようにして、名前をリファクタリングした場合、スローステートメントに
波及

C#8は、プロジェクトでオンにできるコンパイラオプションであるnull許容参照型をサポートするようになりました。docs.microsoft.com/en-us/dotnet/csharp/nullable-references
ポールステグラー

回答:


69

残念ながら、コンパイル時には何も利用できません。

私は少しハッキーな解決策を持っています最近、ブログに投稿した、新しい構造体と変換を使用。

コードコントラクト関連の .NET 4.0では、人生はずっと良くなります。実際の言語構文と非null可能性に関するサポートがあれば非常に便利ですが、コードコントラクトは非常に役立ちます。

MiscUtilには、ThrowIfNullと呼ばれる拡張メソッドもあるので、少し簡単になります。

最後のポイント-「if (null == arg)」の代わりに「if (arg == null)」を使用する理由は何ですか?後者は読みやすく、Cで前者が解決する問題はC#には当てはまりません。


2
>残念ながら、コンパイル時には何も利用できません。> ...>実際の言語構文とnull以外の可能性に関するサポートがあればなお良いと思います。コンパイル時のエラーが発生するのも見てほしい。
AndrewJacksonZA

2
@ Jon、boolへの暗黙的なキャストが定義されている場合、「if(arg = null)」は機能しませんか?私はそれがおかしいように見えるかもしれないことを認めますが、それはコンパイルします...
トーマス・S・トリアス

11
@ ThomasS.Trias:はい、その非常に不明瞭なエッジの場合には、組み合わせてそのコードの周りのテストの欠如と組み合わせるタイプミスを、そこにいると、あなたは問題で終わるだろう。私が考えるその点によって、あなたは:)しかし、より大きな問題を抱えている
ジョンスキート

4
@ジョン:確かに。私は私の愛するヨーダの状態をあきらめると思います。:-)
Thomas S. Trias

1
@SebastianMach:理由if (null == x)は自然言語の違いによるものだとは思いません。私は、例を介して伝播するだけの時代遅れのスタイルについて本当に信じています
Jon Skeet

21

私はこの質問に非常に遅れていることを知っていますが、C#の最新の主要なイテレーションがリリースに近づき、リリースされるにつれて、答えが適切になると思います。C#8.0では大きな変更が行われ、C#ではすべての型がnullではないと見なされます。

Mads Torgersenによると:

問題は、null参照が非常に役立つことです。C#では、これらはすべての参照タイプのデフォルト値です。デフォルト値は他に何でしょうか?他に何を割り当てるかを決定できるまで、変数には他にどのような値がありますか?新たに割り当てられた参照の配列を埋めるまで、他にどのような値を用意することができますか?

また、ヌルはそれ自体が賢明な値である場合もあります。たとえば、フィールドに値がないことを表現したい場合があります。パラメータに「何も」を渡さなくても問題ないこと。ただし、重点が置かれることもあります。そして、ここに問題の別の部分があります。C#のような言語では、ここのnullが適切であるかどうかを表現できません。

したがって、Madsによって概説されている解決策は次のとおりです。

  1. 参照がnullにならないようにする方が一般的です。null可能な参照型はよりまれな種類になるため(どの程度かを示すための適切なデータはありません)、新しい参照が必要なものです。

  2. 言語には、null許容値型の概念と構文があります。2つの間の類似性により、言語の追加が概念的に簡単になり、言語学的に単純になります。

  3. あなたが積極的にそれらを望んでいると決めない限り、あなた自身やあなたの消費者に厄介なnull値を負担させるべきではないのは正しいようです。それらの不在ではなく、ヌルは明示的にオプトインする必要があるものでなければなりません。

必要な機能の例:

public class Person
{
     public string Name { get; set; } // Not Null
     public string? Address { get; set; } // May be Null
}

プレビューはVisual Studio 2017、15.5.4+プレビューで利用できます。


これがC#8.0の一部になったことがあるかどうか誰か知っていますか?
TroySteven

@TroyStevenはい、あります。VisualStudioの設定を介してオプトインする必要があります。
グレッグ

@TroyStevenこれに関するドキュメントです。 docs.microsoft.com/en-us/dotnet/csharp/nullable-references
Greg

いいですね、動作する前に有効にする必要があるようです。これは下位互換性に優れています。
-TroySteven

15

私はこれが非常に古い質問であることを知っていますが、これはここにありませんでした:

ReSharper / Riderを使用する場合は、Annotated Frameworkを使用できます。

編集:私はこの回答に対してランダムに-1を取得しました。それはいいです。C#8.0以降のプロジェクトでは推奨されないアプローチですが、それでも有効であることに注意してください(理由を理解するには、Gregの回答を参照してください)。


1
興味深いことに、コンパイルされたアプリケーションはデフォルトでJetBrains.Annotations.dllへの参照を持たないため、アプリケーションと共に配布する必要はありません
。JetBrains

9

エンタープライズライブラリのバリデータを確認してください。あなたは次のようなことができます:

private MyType _someVariable = TenantType.None;
[NotNullValidator(MessageTemplate = "Some Variable can not be empty")]
public MyType SomeVariable {
    get {
        return _someVariable;
    }
    set {
        _someVariable = value;
    }
}

次に、コードを検証するときに、次のようにします。

Microsoft.Practices.EnterpriseLibrary.Validation.Validator myValidator = ValidationFactory.CreateValidator<MyClass>();

ValidationResults vrInfo = InternalValidator.Validate(myObject);

0

きれいではありませんが:

public static bool ContainsNullParameters(object[] methodParams)
{
     return (from o in methodParams where o == null).Count() > 0;
}

あなたはContainsNullParametersメソッドでももっと創造的になることができます:

public static bool ContainsNullParameters(Dictionary<string, object> methodParams, out ArgumentNullException containsNullParameters)
       {
            var nullParams = from o in methodParams
                             where o.Value == null
                             select o;

            bool paramsNull = nullParams.Count() > 0;


            if (paramsNull)
            {
                StringBuilder sb = new StringBuilder();
                foreach (var param in nullParams)
                    sb.Append(param.Key + " is null. ");

                containsNullParameters = new ArgumentNullException(sb.ToString());
            }
            else
                containsNullParameters = null;

            return paramsNull;
        }

もちろん、インターセプターやリフレクションを使用することもできますが、オーバーヘッドはほとんどなく、簡単に追跡/使用できます。


3
このようなクエリを使用した非常に悪い習慣:return (from o in methodParams where o == null).Count() > 0; 使用:return methodParams.Any(o=>o==null);大きなコレクションではるかに速くなります
ヤバノスタ

なぜ例外を通過させるのですか?投げてみませんか?
マーティンカポディッチ2013年

-4

わかりました、この返信は少し遅れていますが、ここに私がそれを解決する方法があります:

public static string Default(this string x)
{
    return x ?? "";
}

この拡張メソッドを使用すると、nullと空の文字列を同じものとして扱うことができます。

例えば

if (model.Day.Default() == "")
{
    //.. Do something to handle no Day ..
}

どこでもdefaultを呼び出すことを覚えておかなければならないので、理想的ではありませんが、これは1つの解決策です。


5
これは(x == null)チェックよりも良い/簡単ですか?またはString.IsNotNullOrEmpty関数。
バタビア

string.IsNotNullOrEmptyあなたが気になるものを左側に置くことの砂糖以外は本当にそれほど優れていません。他の関数(長さ、連結)などに供給することができます。
Martin Capodici 16年

@MartinCapodiciまた、これにより、null()でインスタンスメソッド(Default())を呼び出しても安全であるような錯覚が生じます。拡張メソッドがnullに対してチェックされないことは知っていますが、私の目は気づいておらず、コードにすでに想像されています::)model.Day?model?.Day?.Default()
Alb
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.