を比較します。 約5つのレベルの子オブジェクトがあります。最善の方法は、私が<strong><code>Object1</code></strong>と<strong><code>Object2</code></strong>のような2つの複合オブジェクトを持つ2つの複雑なオブジェクト
同じかどうかを知るには、最も速い方法が必要です。
どのようにC#4.0でこれを行うことができますか?
を比較します。 約5つのレベルの子オブジェクトがあります。最善の方法は、私が<strong><code>Object1</code></strong>と<strong><code>Object2</code></strong>のような2つの複合オブジェクトを持つ2つの複雑なオブジェクト
同じかどうかを知るには、最も速い方法が必要です。
どのようにC#4.0でこれを行うことができますか?
Object.Equals
とObject.GetHashCode
のメソッドをすべてのカスタムタイプでオーバーライドすることと組み合わせて、IEquatable<T>
を実装します。コンポジット型の場合は、含まれる型の中で含まれる型 'Equals
を呼び出します。含まれているコレクションについては、各要素の内部でIEquatable<T>.Equals
またはObject.Equals
を呼び出すSequenceEqual
拡張メソッドを使用してください。このアプローチでは、明らかに型の定義を拡張する必要がありますが、その結果はシリアル化を含む一般的なソリューションよりも高速です。
を編集します。ここには、3つのレベルの入れ子があるような複雑な例があります。
値型の場合、通常はEquals
メソッドを呼び出すことができます。フィールドまたはプロパティが明示的に割り当てられていない場合でも、それらはデフォルト値を持ちます。
参照型の場合は、最初にReferenceEquals
を呼び出して、参照の等しいかどうかを確認する必要があります。これは、同じオブジェクトを参照しているときに効率が向上するためです。また、両方の参照がnullの場合も処理します。チェックに失敗した場合は、インスタンスのフィールドまたはプロパティがnullでないことを確認し(NullReferenceException
を避けるため)、Equals
メソッドを呼び出します。メンバーが正しく型付けされているので、IEquatable<T>.Equals
メソッドは、オーバーライドされたObject.Equals
メソッド(型キャストのために実行がわずかに遅くなります)をバイパスして直接呼び出されます。
Object.Equals
を無効にすると、Object.GetHashCode
も上書きされます。私は簡潔さのために以下ではそうしなかった。
public class Person : IEquatable<Person>
{
public int Age { get; set; }
public string FirstName { get; set; }
public Address Address { get; set; }
public override bool Equals(object obj)
{
return this.Equals(obj as Person);
}
public bool Equals(Person other)
{
if (other == null)
return false;
return this.Age.Equals(other.Age) &&
(
object.ReferenceEquals(this.FirstName, other.FirstName) ||
this.FirstName != null &&
this.FirstName.Equals(other.FirstName)
) &&
(
object.ReferenceEquals(this.Address, other.Address) ||
this.Address != null &&
this.Address.Equals(other.Address)
);
}
}
public class Address : IEquatable<Address>
{
public int HouseNo { get; set; }
public string Street { get; set; }
public City City { get; set; }
public override bool Equals(object obj)
{
return this.Equals(obj as Address);
}
public bool Equals(Address other)
{
if (other == null)
return false;
return this.HouseNo.Equals(other.HouseNo) &&
(
object.ReferenceEquals(this.Street, other.Street) ||
this.Street != null &&
this.Street.Equals(other.Street)
) &&
(
object.ReferenceEquals(this.City, other.City) ||
this.City != null &&
this.City.Equals(other.City)
);
}
}
public class City : IEquatable<City>
{
public string Name { get; set; }
public override bool Equals(object obj)
{
return this.Equals(obj as City);
}
public bool Equals(City other)
{
if (other == null)
return false;
return
object.ReferenceEquals(this.Name, other.Name) ||
this.Name != null &&
this.Name.Equals(other.Name);
}
}
私はと言うでしょう:
Object1.Equals(Object2)
は、あなたが探しているものだろう。それは、オブジェクトが同じかどうか、つまりあなたが求めているように見えるかどうかを調べる場合です。
すべての子オブジェクトが同じかどうかを確認する場合は、Equals()
メソッドのループで実行してください。
私はあなたが文字通り同じオブジェクトを指しているわけではないと仮定します
Object1 == Object2
次の2つの
memcmp(Object1, Object2, sizeof(Object.GetType())
間のメモリの比較を行うことを考えるかもしれない。しかしそれはさえない
実際のコードはC#で:)すべてのデータがヒープ上に作成されている可能性があるため、メモリは連続していないため、2つのオブジェクトの等価性を無関係な方法で比較することはできません。一度に1つずつ、カスタム方法で各値を比較する必要があります。
クラスにIEquatable<T>
インターフェイスを追加し、お使いのタイプにカスタムEquals
メソッドを定義することを検討してください。次に、その方法で、各値を手動でテストします。処理をやり直すことができる場合は、同封のタイプにIEquatable<T>
を再度追加してください。
class Foo : IEquatable<Foo>
{
public bool Equals(Foo other)
{
/* check all the values */
return false;
}
}
これを行う1つの方法は、関係する各タイプのEquals()
を上書きすることです。たとえば、最上位レベルのオブジェクトは、Equals()
をオーバーライドして、すべての5つの子オブジェクトのEquals()
メソッドを呼び出します。これらのオブジェクトはすべて、Equals()
をオーバーライドする必要があります。カスタムオブジェクトであると仮定して、トップレベルオブジェクトの等価チェックを実行するだけで階層全体を比較できるようになります。
IEquatable<T>
Equals
のインタフェースを持つインタフェースを使用してください。
IEquatableを実装したくない場合は、常にReflectionを使用してすべてのプロパティを比較できます。値型の場合は比較してください。それらが参照型の場合は、関数を再帰的に呼び出して、その "内部"プロパティを比較します。
私はperformaceについては考えていませんが、単純さについてです。ただし、オブジェクトの正確な設計に依存します。あなたのオブジェクトの形状に応じて複雑になる可能性があります。しかし、そこにいくつかのソリューションは、あなたは、このように、そこに使用することができていること:あなたが最速の方法を意味し、最速で、それまたはコードを実装する場合
は私は知りませんそれは速く走る。必要があるかどうかを知る前に最適化すべきではありません。 Premature optimization is the root of all evil
'IEquatable
実行する回数equalsメソッド:1、10、100、100、100万?それは大きな違いになります。何も実装せずに汎用ソリューションを使用することができれば、貴重な時間を無駄にすることはありません。遅すぎる場合は、IEquatableを実装する時間です(キャッシュ可能な、またはインテリジェントなGetHashCodeを作成しようとしているかもしれません)。Reflectionのスピードについては、それが遅くなることに同意する必要があります。つまりPropertyInfos Typesを再利用するかどうかなど)。 – JotaBe
そのギブスには書類がありません... – Worthy7
を比較しますあなたが他のファイルで、この静的クラスを参照すると
using System;
using System.IO;
using System.Runtime.Serialization.Json;
using System.Text;
public static class MySerializer
{
public static string Serialize(this object obj)
{
var serializer = new DataContractJsonSerializer(obj.GetType());
using (var ms = new MemoryStream())
{
serializer.WriteObject(ms, obj);
return Encoding.Default.GetString(ms.ToArray());
}
}
}
を(あなたがメソッドにオブジェクト、コレクション、などのANYTYPEを渡すことができます)、あなたはこれを行うことができます。
Person p = new Person { Firstname = "Jason", LastName = "Argonauts" };
Person p2 = new Person { Firstname = "Jason", LastName = "Argonaut" };
//assuming you have already created a class person!
string personString = p.Serialize();
string person2String = p2.Serialize();
これで、.Equalsを使用して比較することができます。 オブジェクトがコレクション内にあるかどうかを確認するために、これを使用します。それは本当にうまくいく。あなたはこの問題解決するために、拡張メソッド、再帰を使用することができます
オブジェクトの内容が浮動小数点数の配列である場合はどうなりますか?それらを文字列に変換することは非常に非効率的であり、変換は 'CultrureInfo'で定義された変換の対象となります。これは、内部データがほとんど文字列と整数の場合にのみ機能します。それ以外の場合は災害になります。 – ja72
新しいディレクターがC#を取り除いてPythonに置き換えるように指示した場合はどうなりますか?開発者として、もし何か問題がどこかに止まらなければならないかどうかを知る必要があります。問題を次の問題に解決してください。あなたが今までに時間を得たら、それに戻ってください... – ozzy432836
Pythonは構文と使用法の点でMATLABに似ています。静的型安全な言語からPythonのようなミッシュマッシュスクリプトに移行するのは本当に良い理由です。 – ja72
:(オブジェクトが非常に複雑である場合)
public static bool DeepCompare(this object obj, object another)
{
if (ReferenceEquals(obj, another)) return true;
if ((obj == null) || (another == null)) return false;
//Compare two object's class, return false if they are difference
if (obj.GetType() != another.GetType()) return false;
var result = true;
//Get all properties of obj
//And compare each other
foreach (var property in obj.GetType().GetProperties())
{
var objValue = property.GetValue(obj);
var anotherValue = property.GetValue(another);
if (!objValue.Equals(anotherValue)) result = false;
}
return result;
}
public static bool CompareEx(this object obj, object another)
{
if (ReferenceEquals(obj, another)) return true;
if ((obj == null) || (another == null)) return false;
if (obj.GetType() != another.GetType()) return false;
//properties: int, double, DateTime, etc, not class
if (!obj.GetType().IsClass) return obj.Equals(another);
var result = true;
foreach (var property in obj.GetType().GetProperties())
{
var objValue = property.GetValue(obj);
var anotherValue = property.GetValue(another);
//Recursion
if (!objValue.DeepCompare(anotherValue)) result = false;
}
return result;
}
をまたはJSONを使用して比較する あなたはNewtonsoft.Jsonを使用することができます。
public static bool JsonCompare(this object obj, object another)
{
if (ReferenceEquals(obj, another)) return true;
if ((obj == null) || (another == null)) return false;
if (obj.GetType() != another.GetType()) return false;
var objJson = JsonConvert.SerializeObject(obj);
var anotherJson = JsonConvert.SerializeObject(another);
return objJson == anotherJson;
}
最初の解決策は素晴らしいです!私はあなたがJSONをシリアライズしたり、オブジェクト自体にコードを追加したりする必要がないのが好きです。単体テストを比較するときに適しています。 objValueとanotherValueの両方がnullの場合に単純比較を追加することをお勧めしますか?これにより、nullを実行しようとするとNullReferenceExceptionがスローされます.Equals()// ReSharper once once RedundantJumpStatement if(objValue == anotherValue); //リファレンスガード else if(!objValue.Equals(anotherValue))Fail(期待値、実際); –
'CompareEx'を再帰的に呼び出すのではなく、' DeepCompare'を使う理由はありますか? – apostolov
私はオブジェクトを比較するための関数の下でこれを見つけました。
static bool Compare<T>(T Object1, T object2)
{
//Get the type of the object
Type type = typeof(T);
//return false if any of the object is false
if (object.Equals(Object1, default(T)) || object.Equals(object2, default(T)))
return false;
//Loop through each properties inside class and get values for the property from both the objects and compare
foreach (System.Reflection.PropertyInfo property in type.GetProperties())
{
if (property.Name != "ExtensionData")
{
string Object1Value = string.Empty;
string Object2Value = string.Empty;
if (type.GetProperty(property.Name).GetValue(Object1, null) != null)
Object1Value = type.GetProperty(property.Name).GetValue(Object1, null).ToString();
if (type.GetProperty(property.Name).GetValue(object2, null) != null)
Object2Value = type.GetProperty(property.Name).GetValue(object2, null).ToString();
if (Object1Value.Trim() != Object2Value.Trim())
{
return false;
}
}
}
return true;
}
私はそれを使用しており、私にとってはうまくいきます。
非常に簡単な方法は次のとおりです。
リファレンス:using System.Linq;
class Program
{
public class JohnsonObject
{
public int Id { get; set; }
public string Description { get; set; }
}
static void Main()
{
JohnsonObject[] obj01 = new[] { new JohnsonObject { Id = 1, Description = "01" } };
JohnsonObject[] obj02 = new[] { new JohnsonObject { Id = 1, Description = "01" } };
Console.Write("Are equal? = {0}", !obj01.Intersect(obj02).Any());
}
}
public class GetObjectsComparison
{
public object FirstObject, SecondObject;
public BindingFlags BindingFlagsConditions= BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
}
public struct SetObjectsComparison
{
public FieldInfo SecondObjectFieldInfo;
public dynamic FirstObjectFieldInfoValue, SecondObjectFieldInfoValue;
public bool ErrorFound;
public GetObjectsComparison GetObjectsComparison;
}
private static bool ObjectsComparison(GetObjectsComparison GetObjectsComparison)
{
GetObjectsComparison FunctionGet = GetObjectsComparison;
SetObjectsComparison FunctionSet = new SetObjectsComparison();
if (FunctionSet.ErrorFound==false)
foreach (FieldInfo FirstObjectFieldInfo in FunctionGet.FirstObject.GetType().GetFields(FunctionGet.BindingFlagsConditions))
{
FunctionSet.SecondObjectFieldInfo =
FunctionGet.SecondObject.GetType().GetField(FirstObjectFieldInfo.Name, FunctionGet.BindingFlagsConditions);
FunctionSet.FirstObjectFieldInfoValue = FirstObjectFieldInfo.GetValue(FunctionGet.FirstObject);
FunctionSet.SecondObjectFieldInfoValue = FunctionSet.SecondObjectFieldInfo.GetValue(FunctionGet.SecondObject);
if (FirstObjectFieldInfo.FieldType.IsNested)
{
FunctionSet.GetObjectsComparison =
new GetObjectsComparison()
{
FirstObject = FunctionSet.FirstObjectFieldInfoValue
,
SecondObject = FunctionSet.SecondObjectFieldInfoValue
};
if (!ObjectsComparison(FunctionSet.GetObjectsComparison))
{
FunctionSet.ErrorFound = true;
break;
}
}
else if (FunctionSet.FirstObjectFieldInfoValue != FunctionSet.SecondObjectFieldInfoValue)
{
FunctionSet.ErrorFound = true;
break;
}
}
return !FunctionSet.ErrorFound;
}
再帰の原則を使用します。 –
私はこのオブジェクトをRIA Services経由で入手します...これらのオブジェクトにIEquatableを使用してWPFクライアントの下で入手できますか? –
あなたはクラスが自動生成されることを意味しますか?私はRIAサービスを使用していませんが、生成されたクラスは 'partial'として宣言されていると仮定します。この場合、フィールド/フィールドを参照する手作業で追加された部分クラス宣言によって'プロパティを自動生成されたものから削除します。 – Douglas
「アドレスアドレス」が実際に「アドレス[]アドレス」の場合、どのように実装されますか? – guiomie