1

C#の文字列は、nullを使用するだけで「null可能」になる可能性があることを私は知っています。

ただし、null許容型の要点は、コンパイラから助けを得るということです[編集:別名、型エラー:バナナにアップルを追加できません]

そして、この「型システムのハックっぽい」を使用すると、「null可能性は基礎となる型に依存します」は、私が持っている可能性のある保証を破ります(これは、そもそも型システムを使用することの全体的なポイントであるように思われるので、小さな偉業ではありません。 )。

必要に応じて、C#でこれを処理する標準的な方法は何ですか?自分の「null許容」クラスをロールするだけでいいですか?

編集

質問を言い換えさせてください:

C#で、null許容として注釈を付けた変数が、null許容として注釈を付けなかった変数に割り当てられないようにするための標準的な方法は何ですか。

つまり、すべてのタイプの標準的な方法は何ですか、正確には何ですか?キーワードは値型を示します。

4

4 に答える 4

4

特定のメソッドの戻り型がではないことを確認する方法について質問している場合nullは、解決策があります。そのメソッドは値型を返す必要があります。参照型を返すすべてのメソッドは、潜在的にを返す可能性がありますnull。それについてあなたができることは何もありません。

したがって、次のstructように作成して、値型を返すことができます。

public struct SurelyNotNull<T>
{
    private readonly T _value;

    public SurelyNotNull(T value)
    {
        if(value == null)
            throw new ArgumentNullException("value");
        _value = value;
    }

    public T Value
    {
        get { return _value; }
    }
}

文字列を返すことになっているメソッドは、を返すことができSurelyNotNull<string>ます。

このアプローチの問題は次のとおりです。
それは機能しません。メソッドの戻り値はそうではないことが保証されていますがnull、の戻り値はそうでSurelyNotNull<T>.Valueはありません。一見すると、nullではないことが保証されているように見えます。ただし、これが原因である可能性があります。別のコンストラクターが定義されている場合でも
、すべての構造体には暗黙的でパブリックなパラメーターなしのコンストラクターがあります。次のコードは有効であり、上記 のコードでコンパイルされます。
struct

new SurelyNotNull<string>();

結論:
C#では、自分がやろうとしていることを達成することはできません。
このアプローチは引き続き使用できます。誰かがこのタイプを使用してもnull値を生成する可能性があることを理解する必要があります。このシナリオですばやく失敗するには、のゲッターにチェックを追加し、がnullValueの場合は例外をスローすることをお勧めします。_value

于 2013-02-19T17:21:35.143 に答える
2

NotNull属性のようなものが必要です。これらを使用すると、コンパイル時の警告とエラーが発生し、場合によっては、NotNull属性へのNULL値の割り当てに関するIDEフィードバックが提供されます。

この質問を参照してください:C#:NotNullおよびCanBeNull属性を実装して使用する方法

于 2013-02-19T18:02:18.287 に答える
2

Daniel Hilgarth が指摘したように、これを達成するための確実な方法はありません。私の提案は彼の提案に似ていますが、安全性がいくらか追加されています。プログラム全体でラッパー型を使用するコストよりもメリットの方が大きいかどうかは、自分で判断できます。

struct NonNull<T> where T : class {
    private readonly T _value;
    private readonly bool _isSafe;

    public NonNull(T value) {
        if (value == null)
            throw new ArgumentNullException();
        _value = value;
        _isSafe = true;
    }
    public T Value {
        get {
            if (_isSafe) return _value;
            throw new ArgumentNullException();
        }
    }
    public static implicit operator T(NonNull<T> nonNull) {
        return nonNull.Value;
    }
}

static class NonNull {
    public static NonNull<T> Create<T>(T value) where T : class {
        return new NonNull<T>(value);
    }
}

ラッパー型は主に意図を自己文書化するためのものであるため、ゼロで初期化された構造体でバイパスすることはほとんどありませんが、正しく初期化されたことを示すフラグを保持します。その明らかに異常なケースではArgumentNullException、値にアクセスするときに をスローします。

class Program {
    static void Main(string[] args) {
        IsEmptyString(NonNull.Create("abc")); //false
        IsEmptyString(NonNull.Create("")); //true
        IsEmptyString(null); //won't compile
        IsEmptyString(NonNull.Create<string>(null)); //ArgumentNullException 
        IsEmptyString(new NonNull<string>()); //bypassing, still ArgumentNullException
    }

    static bool IsEmptyString(NonNull<string> s) {
        return StringComparer.Ordinal.Equals(s, "");
    }
}

さて、これは時折 NRE よりも優れていますか? 多分。定型引数のチェックを大幅に節約できます。あなたの状況にとって価値があるかどうかを判断する必要があります。F# が提供するようなコンパイラ サポートが不足しているため、コンパイル時の null 安全性を提供する方法はありませんが、(ほぼ間違いなく) 実行時の安全性を緩和することはできます。

Microsoft のカスタマー フィードバック サイトでこの問題に賛成票を投じることをお勧めします: C# で null 非許容参照型を追加する

于 2013-02-19T17:38:06.800 に答える
0

すべての参照型は null 許容です。文字列は参照型です。

于 2013-02-19T16:26:58.687 に答える