==演算子をオーバーロードする必要がありますか?
-
08-07-2019 - |
質問
C#で ==
演算子は実際にどのように機能しますか?クラス A のオブジェクトを比較するために使用された場合、 A のすべてのプロパティと一致するか、同じメモリ位置へのポインタを探します(または他に何か?)
架空の例を作成しましょう。 Twitter APIを利用するアプリケーションを作成しており、テキスト、送信者、日付と時刻、ソースなど、1つのツイートのすべてのプロパティを持つ Tweet クラスを持っています。クラス Tweet のオブジェクトを同等に比較したいのですが、使用できます:
Tweet a, b;
if (a == b)
{
//do something...
}
a と b の間の Tweet クラスのすべてのプロパティの等価性をチェックしますか?
そうでない場合、 ==
演算子をオーバーロードしてすべてのフィールドの等価性を明示的にチェックするのが正しいアプローチですか?
更新:最初の2つの回答から、私は次のことを想定しています:
- クラスの
==
演算子または Equals メソッドがオーバーロードされていない場合、 object <の==
演算子/ em>クラスが使用されます。 - object クラスの
==
演算子は、メモリの場所が等しいかどうかをチェックします。 - このタスクを実行するには、
==
演算子または Equals メソッドをオーバーロードする必要があります。 - オーバーロードでは、プロパティの等価性を手動でチェックする必要があるため、ループでなど、半自動でそれを行う方法はありませんか?
更新#2: reflection を使用して、 ==
演算子のプロパティの等価性をチェックできるというコメントをYuriyが作成しました。 。これをどのように行うことができますか?サンプルコードを教えてください。ありがとう!
解決
MSDNには、例があります。方法:
public override bool Equals(object o)
{
try
{
return (bool) (this == (DBBool) o);
}
catch
{
return false;
}
}
その後、==と!=をオーバーロードします:
// Equality operator. Returns dbNull if either operand is dbNull,
// otherwise returns dbTrue or dbFalse:
public static DBBool operator ==(DBBool x, DBBool y)
{
if (x.value == 0 || y.value == 0) return dbNull;
return x.value == y.value? dbTrue: dbFalse;
}
// Inequality operator. Returns dbNull if either operand is
// dbNull, otherwise returns dbTrue or dbFalse:
public static DBBool operator !=(DBBool x, DBBool y)
{
if (x.value == 0 || y.value == 0) return dbNull;
return x.value != y.value? dbTrue: dbFalse;
}
そして、GetHashメソッドをオーバーロードすることを忘れないでください。
編集:
比較でリフレクションを使用するための次の簡単なサンプルを書きました。これはもっと包括的である必要があります。人々が私に望んでいるなら、私はそれについてブログをしようとするかもしれません:
public class TestEquals
{
private int _x;
public TestEquals(int x)
{
this._x = x;
}
public override bool Equals(object obj)
{
TestEquals te = (TestEquals)obj;
if (te == null) return false;
foreach (var field in typeof(TestEquals)
.GetFields(BindingFlags.NonPublic | BindingFlags.Instance))
{
if (!field.GetValue(this).Equals(field.GetValue(te)))
return false;
}
return true;
}
}
他のヒント
参照型の場合、 ==
演算子と Equals()
メソッドの両方のデフォルト実装は、両方のオブジェクトが同じ参照を持っていることを単純にチェックするため、同じインスタンス。
2つの異なるオブジェクトの内容が等しいことを確認する場合は、何らかの方法で自分で実行するコードを記述する必要があります。リフレクション( MbUnit テストフレームワークはこれらの行に沿って何かを行う)を行うことができますが、重いパフォーマンスのペナルティと、とにかく期待したとおりに動作しない可能性が高く、 ==
または Equals
および GetHashCode
を実装する必要がありますハンド。
適切な方法は、こちら。
aとbの間のTweetクラスのすべてのプロパティの等価性をチェックしますか?
いいえ
そうでない場合、==演算子をオーバーロードしてすべてのフィールドの等価性を明示的にチェックするのが正しいアプローチでしょうか?
== 演算子をオーバーロードするか、 Equals 関数をオーバーロードできます。
編集
@Yuriyは、すべての非パブリック変数をコンパイルする良い例を示しました。私も例を書いたので、ここにあります(私のプロパティを比較します)
class TwitterItem
{
private string myValue = "default value";
public string Value1
{
get { return myValue; }
set { myValue = value; }
}
public string Value2
{
get { return myValue; }
set { myValue = value; }
}
public string Value3
{
get { return myValue; }
set { myValue = value; }
}
public override bool Equals(object obj)
{
if (base.Equals(obj)) return true;
Type type = typeof(TwitterItem);
PropertyInfo[] properties = type.GetProperties();
foreach (PropertyInfo property in properties)
{
if (false == property.GetValue(this, null).Equals(property.GetValue(obj, null)))
return false;
}
return true;
}
}
リフレクションを使用してプロパティを比較できます:
var a = new Entity() { Name = "test", ID = "1" };
var b = new Entity() { Name = "test", ID = "1" };
var c = new Entity() { Name = "test", ID = "2" };
System.Diagnostics.Debug.WriteLine(a.Equals(b));//Returns true
System.Diagnostics.Debug.WriteLine(a.Equals(c));//Returns false
public class Entity
{
public string Name { get; set; }
public string ID { get; set; }
public override bool Equals(object obj)
{
var t = obj.GetType();
foreach (var p in t.GetProperties())
{
if (t.GetProperty(p.Name).GetValue(obj, null) != t.GetProperty(p.Name).GetValue(this, null))
return false;
}
return true;
}
}