これは私が今日まで気付いていなかったものです。明らかに、多用されたタプルクラス(Tuple<T>
、Tuple<T1, T2>
など)の.NET実装は、等価ベースの操作が実行されるときに値タイプのボクシングペナルティを発生させます。ここで.NETタプルと同等のパフォーマンス
は、クラスは一種のフレームワーク(ILSpyを介してソース)に実装されている方法です。
public class Tuple<T1, T2> : IStructuralEquatable
{
public T1 Item1 { get; private set; }
public T2 Item2 { get; private set; }
public Tuple(T1 item1, T2 item2)
{
this.Item1 = item1;
this.Item2 = item2;
}
public override bool Equals(object obj)
{
return this.Equals(obj, EqualityComparer<object>.Default);
}
public override int GetHashCode()
{
return this.GetHashCode(EqualityComparer<object>.Default);
}
public bool Equals(object obj, IEqualityComparer comparer)
{
if (obj == null)
{
return false;
}
var tuple = obj as Tuple<T1, T2>;
return tuple != null
&& comparer.Equals(this.Item1, tuple.Item1)
&& comparer.Equals(this.Item2, tuple.Item2);
}
public int GetHashCode(IEqualityComparer comparer)
{
int h1 = comparer.GetHashCode(this.Item1);
int h2 = comparer.GetHashCode(this.Item2);
return (h1 << 5) + h1^h2;
}
}
私が見る問題はそれが2段のボクシングアンボクシングの原因である、Equals
コール、1のために言って、 comparer.Equals
では、2つのアイテム、EqualityComparer<object>
は非汎用Equals
を呼び出し、内部でアイテムを元のタイプにunboxする必要があります。私は平等を見て驚きました
public override bool Equals(object obj)
{
var tuple = obj as Tuple<T1, T2>;
return tuple != null
&& EqualityComparer<T1>.Default.Equals(this.Item1, tuple.Item1)
&& EqualityComparer<T2>.Default.Equals(this.Item2, tuple.Item2);
}
public override int GetHashCode()
{
int h1 = EqualityComparer<T1>.Default.GetHashCode(this.Item1);
int h2 = EqualityComparer<T2>.Default.GetHashCode(this.Item2);
return (h1 << 5) + h1^h2;
}
public bool Equals(object obj, IEqualityComparer comparer)
{
var tuple = obj as Tuple<T1, T2>;
return tuple != null
&& comparer.Equals(this.Item1, tuple.Item1)
&& comparer.Equals(this.Item2, tuple.Item2);
}
public int GetHashCode(IEqualityComparer comparer)
{
int h1 = comparer.GetHashCode(this.Item1);
int h2 = comparer.GetHashCode(this.Item2);
return (h1 << 5) + h1^h2;
}
は、.NETタプルクラスでこの方法を実装:
は代わりになぜ彼らのような何かをしないだろう。私は辞書の1つでタプルタイプをキーとして使用していました。
最初のコードに示されているようにこれを実装しなければならない理由はありますか?その場合、このクラスを利用するのはやめてください。
私は、コードのリファクタリングと重複しないデータが大きな問題であったはずだと思います。同じ非ジェネリック/ボクシングの実装はIStructuralComparable
にもなりましたが、IStructuralComparable.CompareTo
はあまり使われていないので、よく問題になりません。 Tuple<DateTime, DateTime>
フィールド1000000回のEquals
コールのカップルのため
public override bool Equals(object obj)
{
return this.Equals(obj, EqualityComparer<T1>.Default, EqualityComparer<T2>.Default);
}
public bool Equals(object obj, IEqualityComparer comparer)
{
return this.Equals(obj, comparer, comparer);
}
private bool Equals(object obj, IEqualityComparer comparer1, IEqualityComparer comparer2)
{
var tuple = obj as Tuple<T1, T2>;
return tuple != null
&& comparer1.Equals(this.Item1, tuple.Item1)
&& comparer2.Equals(this.Item2, tuple.Item2);
}
:
は私はこのようなまだ少ない課税である第三のアプローチは、(のみ必需品)を用いて、上記2つのアプローチベンチマーク。これは結果である:
第1のアプローチ(元の.NET実装) - 310ミリ秒
第2のアプローチを - 60ミリ秒
3アプローチ - デフォルトの実装は130ミリ秒
最適解より約4〜5倍遅くなります。
「IEqualityComparer
@MarcinJuraszekそれはどうですか? 'Tuple <,>'はこれらの定義を持つ 'IStructuralEquatable'を実装しています。' bool Equals(object other、IEqualityComparer comparer); int GetHashCode(IEqualityComparer comparer); ' – nawfal
" ...多用されたタプルクラス... "。あなたの問題があります! – Gusdor