21

空の参照型を呼び出すと例外が発生する理由を誰かが親切に説明してくれませんかToString()(私の考えでは、これは完全に理にかなっています。何もメソッドを呼び出すことはできません) 。動作はタイプ間で一貫していると思っていたので、これは私にとって非常に驚きでした。ToString()Nullable(Of T)String.Empty

Nullable<Guid> value = null;
Stock stock = null;
string result = value.ToString(); //Returns empty string
string result1 = stock.ToString(); //Causes a NullReferenceException
4

6 に答える 6

20

Nullable<T>は実際には、実際にはではなくstructのように動作するためのコンパイラサポートと実装サポートを備えています。nullnull

表示されているのは、実装間の衝突ですnull。これにより、他の参照型と同じように自然に処理できますが、Nullable<T>実際にはnullではなく、その中の値がnullであるため、メソッド呼び出しが発生します。

視覚的には機能しないように見えます。これはバックグラウンドで何が行われているかがわからないためです。

null参照型で拡張メソッドを呼び出すと、他のそのような視覚的なトリックが見られます...呼び出しは(視覚的な期待に反して)機能します。これは、内部でnullインスタンスをパラメーターとして渡す静的メソッド呼び出しに解決されるためです。

Nullable <T>型は舞台裏でどのように機能しますか?

于 2012-08-03T07:59:00.183 に答える
6

Nullable は値型であり、への代入により、 andnullで初期化されます。Value=nullHasValue=false

さらに、 Nullable.ToString() は次のように実装されています。

public override string ToString()
{
    if (!this.HasValue)
    {
        return "";
    }
    return this.value.ToString();
}

したがって、あなたが見ているものは期待されています。

于 2012-08-03T07:55:18.523 に答える
4

null 許容型では少し注意が必要です。に設定するとnull、実際nullには参照型ではない(値型です)原因ではありません。このような変数を初期化すると、プロパティがであり、それがisnullである新しい構造体インスタンスが作成されるため、メソッドを呼び出すと、構造体インスタンスでうまく機能します。HasValuefalseValuenullToString

于 2012-08-03T07:55:27.117 に答える
1

呼び出しによって発生した例外は、何らかの理由で呼び出され、null 参照でメソッドを呼び出していますdefault(object).ToString()。一方、参照ではないため、null 参照ではありません。nullと同等の値を持つ値型です。NullReferenceExceptiondefault(int?)

大きな実用的なポイントは、これが行われた場合、次のことが失敗するということです:

default(int?).HasValue // should return false, or throw an exception?

また、nullables と non-nullables を混在させる機能を台無しにしてしまいます。

((int?)null).Equals(1) // should return false, or throw an exception?

そして、以下は完全に役に立たなくなります:

default(int?).GetValueOrDefault(-1);

null を削除して null との比較を強制することもできHasValueますが、null 可能にされた値型の等値オーバーライドが、場合によっては null と比較して true を返すことができるとしたらどうなるでしょうか。それは素晴らしいアイデアではないかもしれませんが、それは可能であり、言語は対処しなければなりません.

null 許容型が導入された理由を振り返ってみましょう。参照型が null になる可能性は、非 null 可能性を強制する努力が払われない限り、参照型の概念に固有のものです。参照型は、何かを参照する型であり、何も参照しない可能性を意味します。nullと呼びます。

多くの場合は面倒ですが、「不明な値」、「有効な値がない」などを表すなど、さまざまな場合にこれを利用できます (たとえば、データベースでnullが意味するものに使用できます)。 .

この時点で、特定の参照がどのオブジェクトも参照しないという単純な事実を超えて、特定のコンテキストでnullに意味を与えました。

これは便利なので、intorDateTimeを null に設定することもできますが、これらは他の何かを参照する型ではないため、これ以上何も参照しない状態になることはできません。哺乳類である私は、羽を失うことがあります。

2.0 で導入された null 許容型は、参照型とは異なるメカニズムを通じて、セマンティックnullを持つことができる値型の形式を提供します。このほとんどは、存在しない場合は自分でコーディングできますが、特別なボクシングおよびプロモーション ルールにより、より賢明なボクシングおよびオペレーターの使用が可能になります。

わかった。NullReferenceExceptionsそれでは、そもそもなぜ起こるのかを考えてみましょう。2 つは避けられず、1 つは C# の設計上の決定です (.NET 全体には当てはまりません)。

  1. 仮想メソッドまたはプロパティを呼び出すか、null 参照のフィールドにアクセスしようとしています。どのオーバーライドを呼び出す必要があるかを調べる方法がなく、そのようなフィールドがないため、これは失敗する必要があります。
  2. 仮想メソッドまたはプロパティを呼び出すか、フィールドにアクセスする null 参照で非仮想メソッドまたはプロパティを呼び出します。これは明らかにポイント 1 のバリアントですが、次の設計上の決定には、途中で失敗するのではなく、最初にこれが失敗することを保証するという利点があります (混乱を招き、長期的な副作用が生じる可能性があります)。 .
  3. 仮想メソッドまたはプロパティを呼び出さない null 参照で非仮想メソッドまたはプロパティを呼び出すか、フィールドにアクセスします。これが許可されるべきではない固有の理由はなく、一部の言語では許可されていますが、C#では、一貫性のためにa を強制するのcallvirtではなく使用することにしました (私は同意するとは言えませんが、そこまでです)。callNullReferenceException

これらのケースはいずれも、null 許容値型にはまったく適用されません。アクセスするフィールドまたはメソッドのオーバーライドを知る方法がない状態に、null 許容値型を配置することはできません。justの全体的な概念は、NullReferenceExceptionここでは意味がありません。

全体として、 a をスローしないことは、null 参照が使用されている場合に限り、他の型NullReferenceException と一貫性があります。

null nullable-type を呼び出すと がスローされる場合があることに注意してください。これは、が仮想ではないGetType()ためGetType()です。値型で呼び出されると、常に暗黙のボクシングが行われます。これは他の値タイプにも当てはまります。

(1).GetType()

は次のように扱われます。

((object)1).GetType()

ただし、null 許容型の場合、ボクシングは falseHasValueを持つものを null に変換するため、次のようになります。

default(int?).GetType()

次のように扱われます。

((object)default(int?)).GetType()

その結果GetType()、null オブジェクトで呼び出されるため、スローされます。

ついでに言うと、これはなぜ偽物NullReferenceTypeがより賢明な設計上の決定であったのかということを私たちにもたらします-その行動を必要とする人々はいつでも箱詰めすることができます. それを通過させたい場合((object)myNullableValue).GetString()は、例外を強制するために言語がそれを特別なケースとして扱う必要がないように使用してください。

編集

ああ、背後にある仕組みについて言及するのを忘れていましたNullReferenceException

のテストNullReferenceExceptionは非常に安価です。ほとんどの場合、問題を無視し、発生した場合に OS から例外をキャッチするためです。つまり、テストはありません

null参照例外の発生/生成の背後にある CLR 実装とは何ですか? を参照してください。そして、どれも null 許容値型では機能しないことに注意してください。

于 2012-08-03T11:26:33.167 に答える
0

MSDNの備考に従って

Guid.ToSTring()メソッド提供された形式指定子に従って、このGuidインスタンスの値の文字列表現を返します。

Nullableに関するMSDNの注釈による

タイプに値を割り当てることができるか、nullを割り当てることができる場合、タイプはnull可能であると言われます。つまり、タイプには値がまったくありません。したがって、null許容型は値を表すことも、値が存在しないことを表すこともできます。たとえば、Stringなどの参照型はnull許容ですが、Int32などの値型はnull可能ではありません。値型は、その型に適切な値のみを表現するのに十分な容量があるため、null許容にすることはできません。nullの値を表現するために必要な追加の容量はありません。

于 2012-08-03T08:04:32.287 に答える
0

定義を調べてみるNullable<>と、オーバーライドの ToString 定義があります。この関数では、ToString がオーバーライドされて String.Empty が返されます。

    // Summary:
    //     Returns the text representation of the value of the current System.Nullable<T>
    //     object.
    //
    // Returns:
    //     The text representation of the value of the current System.Nullable<T> object
    //     if the System.Nullable<T>.HasValue property is true, or an empty string ("")
    //     if the System.Nullable<T>.HasValue property is false.
    public override string ToString();

一方、Stock はカスタム クラスであり、ToString はオーバーライドされていないと想定しています。したがって、デフォルトの動作を使用するため、NullReferenceException が返されます。

于 2012-08-03T07:58:09.003 に答える