web-dev-qa-db-ja.com

Guid == nullはコンパイラで許可されるべきではありません

以下で説明する動作は、.net-3.5のみに固有です。

C#コンパイラで最も驚くべき動作に出くわしました。

私は次のコードを持っています:

Guid g1 = Guid.Empty;
bool b1= (g1 == null);

ええと、Guidはnull許容ではないので、nullと等しくなることはありません比較 2行目で作成しています常にfalseを返します

整数に対して同じことを行うと、コンパイラは警告を発行します結果は常にfalseになると言います:

int x=0;
bool b2= (x==null);

私の質問は次のとおりです:コンパイラがGuidをnullと比較できるのはなぜですか
私の知る限り、結果が常に偽であることはすでにわかっています。
組み込みの変換は、コンパイラーがnullが可能な値であると想定するような方法で行われますか?
ここに何か足りないものはありますか?

47
Luis Filipe

マークは正しいです。独自の等式演算子を定義する値型は、無料で定義されたnull許容バージョンに自動的に取得されます。 2つのnull許容ガイドを使用するnull許容等式演算子は、この状況に適用可能であり、呼び出され、常にfalseを返します。

C#2では、これにより警告が生成されましたが、何らかの理由で、guid-to-nullの警告の生成が停止されましたが、int-to-nullの警告は引き続き生成されます。理由はわかりません。私はまだ調査する時間がありませんでした。

エラーをお詫び申し上げます。 C#3でnull許容ロジックを書き直すときに、警告検出コードパスの1つを台無しにした可能性があります。言語に式ツリーを追加すると、null許容算術演算が実現される順序が大幅に変更されました。私はそのコードを動かして多くの間違いを犯しました。複雑なコードです。

81
Eric Lippert

コンパイラがGuidNullable<Guid>に変換し、それが理にかなっているため、比較は有効です。

警告が発行されないというバグレポートがあります ここ

見る ここここ EricLippertからのより完全な説明。

13
Mark Byers

実際にはギルド== nullがtrueを返す場合

しかし、説明するのはちょっと難しいです。

ORMマッピングフレームワーク(たとえばopenAccess)で、デフォルト値がGuid.EmptyであるGuidフィールドがある場合、休眠シナリオが発生する可能性があります。

  • 新しいGUIDフィールド+プロパティを追加します
  • 古いデータベーススキーマをアップグレードします。この場合、データベース内のすべての値がNULLになります。
  • Guild型のこのnull列を持つオブジェクトにデータを入力すると、もちろんオブジェクトはGuid.Empty値を取得します。ただし、LINQクエリを使用すると... LINQクエリでGuidがまだ入力されていないように見えるため、使用する必要があります。 == null。バグかもしれませんが、これが現状です。

要するに(OpenAccessを使用しますが、おそらくそれだけではありません):

var item = GetItems()。Where(i => i.SomeGuidField == null);は機能し、uはスキーマの更新後にnullGUIDのアイテムを取得します。 item.First()。SomeGuidFieldはEmptyGuidを返します

var item = GetItems()。Where(i => i.SomeGuidField == Guid.Empty);アイテムの入力後にGuid.Emptyになり、空を返す場合でも機能しません結果。

1
JOKe

もちろん、これはGuidの問題だけではありません。 structが通常の方法でoperator ==をオーバーロードする場合、C#の事前定義されたタイプではないstructタイプでも同じ動作が見られます。フレームワークの他の例には、DateTimeおよびTimeSpanが含まれます。

演算子が解除されているため技術的には合法ですが、常にfalseが得られるため、これは有用な比較ではないため、これはコンパイル時の警告に値します。このように、それはプログラマーの間違いを示しています。

Eric Lippertが回答で述べたように、コンパイル時の警告はVisual C#2.0コンパイラに存在していました。バージョン3.0から5.0では、警告が誤って省略されていました(これらの「ユーザー定義」のstruct型では、intのような事前定義された値型ではなく、列挙型ではありません)。

C#6.0(Roslynに基づく)以降、コンパイラーはこのコードの問題を再度検出します。ただし、下位互換性(?!)があるため、いわゆるstrict機能を使用してコードをコンパイルしない限り、警告は発行されません。

.csprojファイルを使用するときにstrictを有効にするには(ほとんどの場合)、Visual Studioからプロジェクトをアンロードし、ファイルを編集して、XML要素を挿入します。

<Features>strict</Features>

<PropertyGroup>ファイルの各.csproj(通常は複数あります)に。次に、警告が表示されます(警告をエラーとして扱うを使用すると、エラーに「プロモート」される可能性があります)。

.csprojを編集できず、コンパイルのためにコマンドラインからmsbuild.exeを呼び出す場合は、次のスイッチを使用します。

/p:Features=strict

msbuild.exeへ。

.csproj(C#コンパイラ)で直接コンパイルするためにcsc.exeファイルを使用しない場合は、次のスイッチを使用してください。

/features:strict

コマンドラインでcsc.exeに移動します。

0