Code Fix

中級

== が参照を比較してしまう理由

classの==は既定でオブジェクトの参照(同一性)を比較します。フィールドの値が同じでも、別々に生成したインスタンスはfalseになります。

なぜエラーが出ないのか

出力: False
(エラーなし)
C#は何も報告しません。文法として正しいためです
出力: False
実際の挙動 — 期待した結果と食い違っている箇所
見つけ方
エラーが出ないので、出力を目で確かめるか、コードを目で追うしかありません。この種の誤りが最も発見が遅れます

このエラーが出る典型パターン

パターン1

 1  class Point { public int X; public int Y; }
 2  class Program {
 3      static void Main(string[] args) {
 4          Point a = new Point { X = 1, Y = 2 };
 5          Point b = new Point { X = 1, Y = 2 };
                                   ^
 6          System.Console.WriteLine(a == b);
 7      }
 8  }
出力: False

クラスの==は既定では参照の比較です。フィールドの値が同じでも別のインスタンスならfalseになります。

直し方: new Point { X = 1, Y = 2 } を a にします。

この問題を解いてみる →

広告
広告スロット(未設定)

パターン2

 1  class Item { public string Name; }
 2  class Program {
 3      static void Main(string[] args) {
 4          Item a = new Item { Name = "pen" };
 5          Item b = new Item { Name = "pen" };
                                 ^
 6          System.Console.WriteLine(a == b);
 7      }
 8  }
出力: False

Nameの値が同じ"pen"でも、別々にnewしたインスタンスは別物として扱われます。

直し方: new Item { Name = "pen" } を a にします。

この問題を解いてみる →

パターン3

 1  class Coord { public double Lat; public double Lng; }
 2  class Program {
 3      static void Main(string[] args) {
 4          Coord a = new Coord { Lat = 35.0, Lng = 139.0 };
 5          Coord b = new Coord { Lat = 35.0, Lng = 139.0 };
                                        ^
 6          System.Console.WriteLine(a == b);
 7      }
 8  }
出力: False

値を比較したい場合はEqualsをオーバーライドするか、recordやstructの利用を検討します。

直し方: new Coord { Lat = 35.0, Lng = 139.0 } を a にします。

この問題を解いてみる →

パターン4

 1  class Box { public int Value; }
 2  class Program {
 3      static void Main(string[] args) {
 4          Box a = new Box { Value = 5 };
 5          Box b = new Box { Value = 5 };
                              ^
 6          System.Console.WriteLine(a == b);
 7      }
 8  }
出力: False

クラスの==は既定では参照の比較です。値が同じでも別インスタンスならfalseになります。

直し方: new Box { Value = 5 } を a にします。

この問題を解いてみる →

パターン5

 1  class Tag { public string Label; }
 2  class Program {
 3      static void Main(string[] args) {
 4          Tag a = new Tag { Label = "x" };
 5          Tag b = new Tag { Label = "x" };
                               ^
 6          System.Console.WriteLine(a == b);
 7      }
 8  }
出力: False

Labelの値が同じでも、別々にnewしたインスタンスは別物として扱われます。

直し方: new Tag { Label = "x" } を a にします。

この問題を解いてみる →

よくある誤解

値が同じなら==がtrueになると期待しがちですが、値の比較にしたい場合はEqualsのオーバーライドやrecord型の利用が必要です。

実務での勘所

独自の値ベースの等価性を実装する場合、Equals(object)だけをオーバーライドするのは実は不十分とされています。GetHashCode()も同時にオーバーライドしないと、値として等しいはずのオブジェクトがDictionaryやHashSetで正しく同じキーとして扱われなくなります(Javaのequals/hashCodeの規約と同じ考え方です)。さらに実務では、object型を経由するEquals(object)だけでなく、IEquatable<T>という汎用インターフェースも実装すると、比較のたびに発生するボックス化やキャストを避けられ、パフォーマンス面でも有利になります。

演習をはじめる

関連するエラー

他の言語ではどうなるか

広告
広告スロット(未設定)