11

似たような質問を見つけました

類似した特性を持つ 2 つの明確に異なるオブジェクトを比較する方法

それは暗黙のうちに、および/または部分的に私の質問に答えるかもしれません。

このオブジェクトを(多くのネストされた条件なしで)比較したいとします。

class ObjectA {
  public string PropertyX { get; set; }
  public char PropertyY { get; set; }
  public long PropertyZ { get; set; }
}

System.String。私は平等または不平等にのみ興味があります (アイデンティティに関する値の範囲ではありません)。

での実装IEquatable<string>ObjectA適切な選択ですか? 何がうまくいくかは気にしません。そのような場合の適切なパターンを特定したいと思います

その他の情報として、 のObjectAシーケンスとして提供されることが多いと考えてくださいIEnumerable<ObjectA>

インスタンスかどう"string" ==かを知る必要はありません。!= objectAソートは含まれません。

編集して明確にする(そして助ける)

申し訳ありませんが、良い質問を書くのは難しい場合があります...

ObjectA比較のために文字列として表すことができないとします (カプセル化に違反することはオプションではありません)。

  • context-1 では、それを と照合する必要がありPropertyYます。

  • PropertyYcontext-2 では、 /に適用されるアルゴリズムと照合する必要がありますPropertyZ

質問の最後にある@Oliverソリューションは、私を再び助けてくれます(そして再び+1します)。カスタム インターフェイスを簡単に定義できます。

interface IContextConverter {
  string ToEquatableStringForContext1();
  string ToEquatableStringForContext2();  
}

私もObjectB同じロジックで異なるプロパティを持っているので、両方ともRAPに違反しないように実装しますIContextConverter(または、より良い名前を見つけることができます) 。

4

3 に答える 3

9

特にコレクション、辞書、LINQなどを操作する場合は、実装しないことを強くお勧めします。これらのメソッドのいずれかが内部のどこかで呼び出され、微妙なバグが発生する可能性があるかどうかはわかりません。IEquatable<string>

異なるタイプの2つのオブジェクトを比較したいという事実のために、単純なものComparer<T>も機能しません。

したがってTypeConverter、オブジェクトを目的のタイプ(この場合はa)に変換するaを作成するかstring、のようなメソッドをオブジェクトに追加し、.ToEquatableString()その出力を使用してオブジェクトを他の文字列と比較します。

これは、別のコレクションの文字列の1つに一致するすべての要素を取得できる例です。

IEnumerable<String> otherElements = new[] {"abc", "def", "ghi" };
IEnumerable<ObjectA> myObjects = GetObjects();

var matchesFound = otherElements.Join( // Take the first collection.
              myObjects, // Take the second collection.
              s => s, // Use the elements in the first collection as key (the string).
              obj => obj.ToEquatableString(),  // Create a string from each object for comparison.
              (s, obj) => obj, // From the matching pairs take simply the objects found.
              StringComparer.OrdinalIgnoreCase); // Use a special string comparer if desired.
于 2013-03-07T16:15:14.793 に答える
2

多くの可能性があります。

ObjectAが の一種であると思われる場合は、ユーザー定義の変換 (暗黙的または明示的) を からへ、または からへ、または両方向にSystem.String記述できます。ObjectASystem.StringSystem.StringObjectA

==and!=演算子を のようなシグネチャでオーバーロードすることもできますoperator ==(ObjectA oa, string s)oa == sと の間には違いがあることに注意してくださいs == oa

これら 2 つの可能性のいずれかが混乱を招く可能性があります。virtual をオーバーライドしEquals(object)たり、オーバーロードを導入したりすることも混乱を招きますEquals(string)。したがって、実装はお勧めしませんIEquatable<string>

のような未使用の名前でメソッドを単純に記述しないのはなぜpublic bool EqualsString(string s)ですか? もちろん、このメソッドを明示的に呼び出す必要がありますが、これにより混乱が少なくなります。別のアイデアは、 signature のコンストラクターを使用してから、public ObjectA(string s)and の「同種」の等価性を実装することObjectAですObjectA

于 2013-03-07T16:40:13.750 に答える
1

注:この特定のケースではこのソリューションを特にお勧めしませんが、このフレームワークを使用して構造体の値の同等性を実装することがよくあります。私たちの分野では難しいトレードオフが一般的であり、適切な警告を伴って、それらに対処する答えは正しいように思われます。

.NET Frameworkが文字列クラスに対してこれを行うのと同じ方法で、クラスにValueEqualityセマムティクスを設計したいと考えています。少なくとも、以下が必要です。

public override bool Equals(object obj) { 
  return (obj is ObjectA) && this == (ObjectA)obj; 
}
bool IEquatable<ObjectA>.Equals(ObjectA rhs) { 
  return this == rhs; 
}
public static bool operator != (ObjectA lhs, ObjectA rhs) { 
  return ! (lhs == rhs); 
}
public static bool operator == (ObjectA lhs, ObjectA rhs) {
  return (lhs.PropertyX == rhs.PropertyX);
}
public override int GetHashCode() { 
  return PropertyX.GetHashCode() 
}

ObjectAと文字列の間の値の比較を可能にするために拡張します。

bool IEquatable<ObjectA>.Equals(string rhs) { 
  return this == rhs; 
}
public static bool operator != (ObjectA lhs, string rhs) { 
  return ! (lhs == rhs); 
}
public static bool operator != (string lhs, ObjectA rhs) { 
  return ! (lhs == rhs); 
}
public static bool operator == (ObjectA lhs, string rhs) {
  return (lhs.PropertyX == rhs);
}
public static bool operator == (string lhs, ObjectA rhs) {
  return (lhs == rhs.PropertyX);
}
于 2013-03-07T16:14:51.347 に答える