2010-03-26 3 views
1

동일한 유형의 개체 모음이 있는데 이것을 DataItem이라고합시다. 사용자는 편집기에서 이러한 항목을보고 편집 할 수 있습니다. 다른 항목 (예 : DataItem 인스턴스의 경우 일종의 diff/merge)을 비교하고 병합 할 수도 있어야합니다.개체에 대한 차이점/병합 기능 (파일이 아님)

DIFF 기능은 항목의 모든 (관련) 속성/필드를 비교하고 가능한 차이점을 찾아야합니다. MERGE 기능은 선택한 차이점을 항목 중 하나에 적용하여 두 인스턴스를 병합 할 수 있어야합니다.

예를 들어 (의사 객체) : 이제

DataItem1 {     DataItem2 { 
    Prop1 = 10     Prop1 = 10 
    Prop2 = 25     Prop2 = 13 
    Prop3 = 0     Prop3 = 5 
    Coll = { 7, 4, 8 }   Coll = { 7, 4, 8, 12 } 
}       } 

, 사용자는 차이의 목록을 제공해야한다 (즉 Prop2, Prop3Coll) 그리고 그는 그가 원하는 어떤 차이 선택할 수 있어야 한 항목의 값을 다른 항목에 할당하여 제거 할 수 있습니다. 또한 그는 DataItem1의 값을 DataItem2 또는 그 반대로 할당 할 것인지 여부를 선택할 수 있어야합니다.

이 기능을 구현하는 데 사용해야하는 일반적인 방법이 있습니까?

이후 또한, 나는 두 시나리오는 기본적 등 속성 할당, 수집 변화를 처리하고 있기 때문에 ICommand 구현을 재사용에 대해 생각합니다 (명령 패턴 사용) 실행 취소/재실행 기능을 제공해야 같은 편집기 .. . 내 생각은이 Difference 병합 작업을 수행하는 데 사용할 수있는 ICommand 속성이있는 Difference 개체를 만드는 것이 었습니다.

Btw : 프로그래밍 언어는 .NET 3.5SP1/4.0을 사용하는 C#입니다. 그러나 이것은 언어에 독립적 인 질문이라고 생각합니다. 어떤 디자인 패턴/아이디어/무엇이든지 환영합니다!

답변

1

그건 내가하는 일입니다. Reflection을 사용하여 속성 값을 비교하기 위해 PropertyDiff 클래스를 사용하는 개체에 대한 "Diff"클래스가 있습니다. 모든 코드를 SO에 붙여 넣기에는 너무 어렵지만 아이디어가 있어야합니다. 비 동일 PropertyDiff 개체의 컬렉션은 유지 또는 삭제할 개체를 선택할 수있는 사용자에게 표시됩니다. 우리는 NHibernate를 사용하여 객체가 메모리에서 변경되고 모든 변경 사항이 트랜잭션에서 지속되도록합니다. 우리는 SQL 명령 모음을 구축 한 오래된 버전을 가지고 있었지만 잘 작동했지만 명령이 동일한 순서와 트랜잭션으로 실행되도록주의해야합니다. 최악의 경우는 예외가 발생하고 두 객체가 모두 FUBAR 인 경우입니다.

PropertyDiff 클래스는 두 개체의 동일한 속성 간의 비교를 나타냅니다. 이는 단순한 속성에만 적용되며 컬렉션을 유지 관리하는 별도의 코드가 있습니다.

public class PropertyDiff 
{ 
    private bool _isEqual; 

    public PropertyDiff(string propertyName, object xvalue, object yvalue) 
    { 
     PropertyName = propertyName; 
     Xvalue = xvalue; 
     Yvalue = yvalue; 
     _isEqual = Xvalue == Yvalue; 
    } 

    public string PropertyName { get; private set; } 
    public object Xvalue { get; private set; } 
    public object Yvalue { get; private set; } 
    public bool IsEqual 
    { 
     get { return _isEqual; } 
    } 

    internal static IList<PropertyDiff> GetPropertyDiffs(IEnumerable<string> properties, object x, object y) 
    { 
     if (x.GetType() != y.GetType()) 
     { 
      throw new ArgumentException("Objects must be of same type"); 
     } 

     var list = new List<PropertyDiff>(); 
     var t = x.GetType(); 

     foreach (string propertyName in properties) 
     { 
      PropertyInfo pi = t.GetProperty(propertyName); 
      if (pi != null) 
      { 
       object xVal = pi.GetValue(x, null); 
       object yVal = pi.GetValue(y, null); 
       PropertyDiff propDiff = new PropertyDiff(propertyName, xVal, yVal); 
       list.Add(propDiff); 
      } 
     } 
     return list; 
    } 
} 

그리고 CompanyDiff 클래스

:

public class CompanyDiff 
    { 
     private List<string> _propertyNames; 
     private IList<PropertyDiff> _propertyDiffs; 

     public CompanyDiff(Company companyX, Company companyY) 
     { 
      this.CompanyX = companyX; 
      this.CompanyY = companyY; 

      // Build list of property names to be checked 
      _propertyNames = new List<string>() 
          { 
           "Type", 
           "Name", 
           "DBA" 
           // etc. 
          }; 

      _propertyDiffs = PropertyDiff.GetPropertyDiffs(_propertyNames, this.CompanyX, this.CompanyY); 
    } 

    public Company CompanyX { get; private set; } 
    public Company CompanyY { get; private set; } 

    public IList<PropertyDiff> PropertyDiffs 
    { 
     get { return _propertyDiffs; } 
    } 
} 
+0

오 와우, 나는 완전한 소스 코드를 기대하지 않았다. :) 감사! 리플렉션 사용에 대해서도 생각했습니다. 그러나 성능 문제가 있기 때문에 사용하지 않을 계획입니다. 대신, 각 클래스에서'Compare (...) '메소드를 사용하여'IDiffable' 인터페이스를 구현하고자했습니다. 리플렉션 기반 접근법으로 어떤 경험을 했습니까 (성능 측면에서)? 나는 각각 약 50 개의 속성을 갖는 약 2000 개의 객체들의 집합을 비교해야 할 것이다 (하나의 클래스가 아니라 재귀 적으로 계산된다). – gehho

+0

성능이 좋았 기 때문에 성능을 측정하지 못했습니다.이것은 우리에게 예외 처리 (중복 된 회사 입력 등)가되기 때문에 성능이 주요 목표는 아닙니다. 나의 조언은 리플렉션을 사용하여 가장 쉬운 접근법을 취하고 현실적인 성능 문제가있는 경우이를 다시 고려하는 것입니다. 즉, 조기에 최적화하지 마십시오. –

+0

감사합니다. 어쩌면 나는 반사에 기반한 접근법을 먼저 시도해 볼 것입니다. 그런 다음 성능 요건을 충족하는지 확인합니다. – gehho