List.ContainsやIndexOfの比較を値で行う

List<T>などでTが参照型の場合、ContainsやIndexOfは値(オブジェクト内容)ではなく、参照先を判定する仕様となっている。

これを、値(オブジェクト内容)で判定させたい場合はどうするのかというと、T型にIEquatable<T>インターフェースをインプリメントして、Equalsメソッドを定義して上げれば良い。

// ノーマルバージョン
public class Person {
	public string Name { get; set; }
	public string Mail { get; set; }
}
var p = new Person() { Name = "T.Sumomo", Mail = "t.sumomo@momo.com" };
var p1 = new Person() { Name = "T.Sumomo", Mail = "t.sumomo@momo.com" };
p == p1
p.Equals(p1)
List<Person> l1 = new List<Person>() { p };
l1.Contains(p1)
l1.IndexOf(p1)
// 値比較バージョン
public class Person1 : IEquatable<Person1> {
	public string Name { get; set; }
	public string Mail { get; set; }
	// 値で比較
	public bool Equals(Person1 other) {
		return other?.Name == Name && other?.Mail == Mail;
	}
}
var p2 = new Person1() { Name = "T.Sumomo", Mail = "t.sumomo@momo.com" };
var p3 = new Person1() { Name = "T.Sumomo", Mail = "t.sumomo@momo.com" };
p2 == p3
p2.Equals(p3)
List<Person1> l2 = new List<Person1>() { p2 };
l2.Contains(p3)
l2.IndexOf(p3)
> p == p1
false
> p.Equals(p1)
false
> l1.Contains(p1)
false
> l1.IndexOf(p1)
-1
>
> p2 == p3
false
> p2.Equals(p3)
true
> l2.Contains(p3)
true
> l2.IndexOf(p3)
0

と、このように値で判定を行う事ができる。

もちろん、内容全部を比較するのでは無く、キーとなるプロパティだけの比較とかでも問題は無い。
ちなみに、Equalsではなく、== operatorをEqualsと同じ内容にしても、ContainsやIndexOfは参照先の比較になってしまう。

まぁ、わざわざクラスに手を入れないで、LINQ使ってもいいのだけど・・・

takezou について

ソフトウェア開発会社(ITと言う言葉は大嫌い)で働く、元技術者。 未だに、社内システム位は作ってますが・・・ プログラミング言語はC#が好き。 好きなことだけ拾って投稿しているので、内容にはあまり期待しないでねw
カテゴリー: .NET, C#, 技術系 パーマリンク

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください