以下で説明する動作は、.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が可能な値であると想定するような方法で行われますか?
ここに何か足りないものはありますか?
マークは正しいです。独自の等式演算子を定義する値型は、無料で定義されたnull許容バージョンに自動的に取得されます。 2つのnull許容ガイドを使用するnull許容等式演算子は、この状況に適用可能であり、呼び出され、常にfalseを返します。
C#2では、これにより警告が生成されましたが、何らかの理由で、guid-to-nullの警告の生成が停止されましたが、int-to-nullの警告は引き続き生成されます。理由はわかりません。私はまだ調査する時間がありませんでした。
エラーをお詫び申し上げます。 C#3でnull許容ロジックを書き直すときに、警告検出コードパスの1つを台無しにした可能性があります。言語に式ツリーを追加すると、null許容算術演算が実現される順序が大幅に変更されました。私はそのコードを動かして多くの間違いを犯しました。複雑なコードです。
実際にはギルド== nullがtrueを返す場合
しかし、説明するのはちょっと難しいです。
ORMマッピングフレームワーク(たとえばopenAccess)で、デフォルト値がGuid.EmptyであるGuidフィールドがある場合、休眠シナリオが発生する可能性があります。
要するに(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になり、空を返す場合でも機能しません結果。
もちろん、これは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
に移動します。