11

我发现了一个类似的问题

如何比较具有相似属性的两个截然不同的对象

这可能会含蓄地和/或部分地回答我的问题。

假设我想比较(没有很多嵌套条件)这个对象:

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.

  • 在上下文 2 中,我必须将其与应用于PropertyY/的算法相匹配PropertyZ

问题末尾的@Oliver解决方案再次帮助我(并再次+1)。我可以简单地定义一个自定义接口:

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

由于我也ObjectB具有相同的逻辑但不同的属性,因此两者都将实现IContextConverter或者我可能会找到更好的名称)避免违反RAP

4

3 回答 3

9

我强烈建议不要实现IEquatable<string>,尤其是在使用集合、字典、LINQ 等时。你真的不知道何时会在内部深处调用这些方法之一,这可能会导致细微的错误。

由于您喜欢比较两个不同类型的对象,因此简单Comparer<T>也行不通。

因此,要么编写 aTypeConverter将您的对象转换为所需的类型(在您的情况下为 a string),要么向您的对象添加一个方法,例如.ToEquatableString()并使用它们的输出将您的对象与其他字符串进行比较。

这是一个示例,您可以获得与另一个集合中的一个字符串匹配的所有元素:

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

有很多可能性。

如果您觉得 anObjectA是一种System.String,您可以编写一个用户定义的转换(隐式或显式)从ObjectAtoSystem.String或 from System.StringtoObjectA或两个方向。

您还可以使用类似的签名重载==and运算符。请注意和之间存在差异。!=operator ==(ObjectA oa, string s)oa == ss == oa

这两种可能性中的任何一种都可能导致混淆。Equals(object)覆盖 virtual或引入重载也会令人困惑Equals(string)。因此我不建议实施IEquatable<string>.

为什么不简单地编写一个未使用名称的方法,例如public bool EqualsString(string s)?然后,您当然必须显式调用此方法,但这会减少混乱。另一个想法是使用签名的构造函数,public ObjectA(string s)然后实现 and 的“同质”ObjectA相等ObjectA

于 2013-03-07T16:40:13.750 回答
1

注意:对于这种特殊情况,我并不特别推荐这个解决方案,但我经常使用这个框架来实现结构的价值平等。在我们的领域中,困难的权衡很常见,解决这些问题的答案,伴随着适当的警告,似乎是有序的。

我认为您希望以与 .NET 框架为字符串类执行此操作的方式相同的方式在您的类上设计值平等语义。至少,以下是必要的:

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 回答