IEnumerable< T>で明確なC#カスタムIEqualityComparerを使用
-
10-07-2019 - |
質問
これが私がやろうとしていることです。 LINQ to XMLを使用してXMLファイルを照会しています。これにより、IEnumerable < T
>ここで、Tは私の「Village」です。このクエリの結果で満たされたクラス。一部の結果が重複しているため、次のようにIEnumerableオブジェクトでDistinct()を実行します。
public IEnumerable<Village> GetAllAlliances()
{
try
{
IEnumerable<Village> alliances =
from alliance in xmlDoc.Elements("Village")
where alliance.Element("AllianceName").Value != String.Empty
orderby alliance.Element("AllianceName").Value
select new Village
{
AllianceName = alliance.Element("AllianceName").Value
};
// TODO: make it work...
return alliances.Distinct(new AllianceComparer());
}
catch (Exception ex)
{
throw new Exception("GetAllAlliances", ex);
}
}
Villageオブジェクトではデフォルトの比較演算子が機能しないため、ここでAllianceComparerクラスに見られるように、カスタム比較演算子を実装しました。
public class AllianceComparer : IEqualityComparer<Village>
{
#region IEqualityComparer<Village> Members
bool IEqualityComparer<Village>.Equals(Village x, Village y)
{
// Check whether the compared objects reference the same data.
if (Object.ReferenceEquals(x, y))
return true;
// Check whether any of the compared objects is null.
if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
return false;
return x.AllianceName == y.AllianceName;
}
int IEqualityComparer<Village>.GetHashCode(Village obj)
{
return obj.GetHashCode();
}
#endregion
}
Distinct()メソッドは機能しません。これは、それを使用してもしなくてもまったく同じ数の結果が得られるからです。もう1つ、通常それが可能かどうかはわかりませんが、AllianceComparer.Equals()に足を踏み入れて、何が問題になる可能性があるかを確認することはできません。
インターネットでこの例を見つけましたが、実装を機能させることができません。
うまくいけば、ここの誰かがここで何が間違っているのかわかるかもしれません! 事前に感謝します!
解決
問題は GetHashCode
にあります。代わりに AllianceName
のハッシュコードを返すように変更する必要があります。
int IEqualityComparer<Village>.GetHashCode(Village obj)
{
return obj.AllianceName.GetHashCode();
}
問題は、 Equals
が true
を返す場合、オブジェクトは同じ Village
オブジェクトの場合とは異なるハッシュコードを持つ必要があることです。同じ AllianceName
を使用します。 Distinct
はハッシュテーブルを内部で構築することで機能するため、異なるハッシュコードが原因でまったく一致しない等しいオブジェクトになります。
同様に、2つのファイルを比較するために、2つのファイルのハッシュが同じでない場合、ファイル自体をチェックする必要はまったくありません。それらは 異なります。それ以外の場合は、それらが実際に同じかどうかを確認し続けます。これが、 Distinct
が使用するハッシュテーブルの動作です。
他のヒント
return alliances.Select(v =&gt; v.AllianceName).Distinct();
IEnumerable&lt; Village&gt;
ではなく、 IEnumerable&lt; string&gt;
を返します。
または行を変更します
return alliances.Distinct(new AllianceComparer());
to
return alliances.Select(v => v.AllianceName).Distinct();