2011-12-22 2 views
1

나는이 방법이라고 MatchNodes이 : 기본 클래스에서 속성/필드를 포함하지 기본적으로 반사를 통해 (모두 T 객체에서 모든 재산과 필드를 얻을 수 IEnumerable<bool> MatchNodes<T>(T n1, T n2)방지 스택 오버 플로우

등을) 그리고 그들을 비교하여 결과를 bool의 IEnumerable로 반환합니다.

원시 유형 또는 문자열을 찾으면 그 사이에 ==을 반환하면됩니다.

컬렉션에서 파생 된 유형을 찾으면 각 구성원을 반복하고 각 구성원에 대해 MatchNodes을 호출합니다 (아야).

다른 형식을 찾으면 각 속성/필드에 대해 MatchNodes을 호출합니다.

내 솔루션은 분명히 스택 오버플로 예외를 요구하지만 객체가 얼마나 깊게 들어갈 지 모르기 때문에 어떻게 더 잘 만들 수 있는지 실마리가 없습니다.

코드 는 (그것이 지옥으로 추한 제발 울지 않으려 고) :

public static IEnumerable<bool> MatchNodes<T>(T n1, T n2) 
    { 
     Func<PropertyInfo, bool> func= null; 

     if (typeof(T) == typeof(String)) 
     { 
      String str1 = n1 as String; 
      String str2 = n2 as String; 
      func = new Func<PropertyInfo, bool>((property) => str1 == str2); 
     } 
     else if (typeof(System.Collections.IEnumerable).IsAssignableFrom(typeof(T))) 
     { 
      System.Collections.IEnumerable e1 = (System.Collections.IEnumerable)n1; 
      System.Collections.IEnumerable e2 = (System.Collections.IEnumerable)n2; 
      func = new Func<PropertyInfo, bool>((property) => 
      { 
       foreach (var v1 in e1) 
       { 
        if (e2.GetEnumerator().MoveNext()) 
        { 
         var v2 = e2.GetEnumerator().Current; 
         if (((IEnumerable<bool>)MatchNodes(v1, v2)).All(b => b == true)) 
         { 
          return false; 
         } 
        } 
        else 
        { 
         return false; 
        } 
       } 
       if (e2.GetEnumerator().MoveNext()) 
       { 
        return false; 
       } 
       else return true; 
      }); 
     } 
     else if (typeof(T).IsPrimitive || typeof(T) == typeof(Decimal)) 
     { 
      func = new Func<PropertyInfo, bool>((property) => property.GetValue(n1, null) == property.GetValue(n2, null)); 
     } 
     else 
     { 
      func = new Func<PropertyInfo, bool>((property) => 
        ((IEnumerable<bool>)MatchNodes(property.GetValue(n1, null), 
        property.GetValue(n2, null))).All(b => b == true)); 
     } 

     foreach (PropertyInfo property in typeof(T).GetProperties().Where((property) => property.DeclaringType == typeof(T))) 
     { 
      bool result =func(property); 
      yield return result; 
     } 

    } 

내가 찾고 있어요 것은 재귀 내 방법을 호출하지 않고 개체로 기어하는 방법입니다.

명확히 편집 예 :

public class Class1 : RandomClassWithMoreProperties{ 
    public string Str1{get;set;} 
    public int Int1{get;set;} 
} 

public class Class2{ 
    public List<Class1> MyClassProp1 {get;set;} 
    public Class1 MyClassProp2 {get;set;} 
    public string MyStr {get;set;} 
} 

MatchNodes(n1,n2)n1.GetType()n2.GetType()Class2은 반환의 경우에 true :

  • MyClassProp1 내부의 모든 Class1 객체가 같은,321있다 모두 0 Int1
  • MyClassProp2
  • MyStr 두 개체

동등한이고 I는 RandomClassWithMoreProperties에서 모든 특성과 비교되지 두 개체 동일한 Str1, Int1을 갖는 개체.

+0

직접 메서드를 다시 작성하지 않고 재귀 적으로 작성할 수있는 모든 메서드를 루프로 작성할 수도 있습니다. 그 어려움은 결코 사소한 일이 될 수는 없지만 그것은 알려진 CS 근본이고 제가 직접 고용 한 것입니다. – user978122

+3

루프 일지라도 개체 그래프의 사이클을 조심해야합니다. 또한, 재귀 호출은'T' 제네릭 매개 변수로'object'를 사용합니다 - 이것은'DeclaringType == typeof (T)'를 검사하기 때문에 당신이 원하는 것이 아닐 것입니다. 너 정확히 뭘 하려구? 아마도 더 좋은 방법이있을 것입니다. –

+0

또한 두 개의 문자열을 주면 무슨 일이 일어나는지 살펴 보자.'typeof (String) .GetProperties()'의 foreach 속성은'func'을 호출 할 것이고, 이것은'str1 == str2'이다. 이것은 아마도 당신이하고자했던 것이 아닙니다. –

답변

1

스택 또는 큐를 사용하여 비교할 속성을 저장할 수 있습니다. 그것은이 라인을 따라 간다 :

var stack = new Stack<Tuple<object, object>>(); 

// prime the stack 
foreach (var prop in n1.GetType().GetProperties()) 
{ 
    stack.Push(Tuple.Create(prop.GetValue(n1), prop.GetValue(n2)); 
} 

while (stack.Count > 0) 
{ 
    var current = stack.Pop(); 

    // if current is promitive: compare 
    // if current is enumerable: push all elements as Tuples on the stack 
    // else: push all properties as tuples on the stack 
} 

당신이 대신 StackQueue를 사용하면 DFS 대신 BFS를 얻을 경우. 또한 HashSet에서 이미 방문한 노드를 추적해야합니다. 또한 n1n2 유형이 동일한 지 확인하기 위해 점검을 추가 할 수 있습니다.

+0

감사합니다, 그것은 내 문제를 해결합니다. 나는 대답으로 받아 들일 것이지만, 나는 나의 해결책을 과도하게 복잡하게했다고 생각한다. 나는 단지 20 ~ 30 개의 클래스에 대해서만해야하기 때문에 각 객체를 수동으로 비교할 수 있습니다. –

0

여기서 좋은 접근 방법은 사용자가 직접 만지는 객체의 탐색 경로를 유지하고 더 깊이 파고 들자마자 전달하는 것입니다. 각각의 새 객체에 대해 이미 본 객체의 그래프에 있는지 여부를 확인하고, 존재한다면 객체가 누락되어 누전 될 수 있습니다 (이미 노드를 보았습니다). 아마도 스택이 적절할 것입니다.

비주기적인 개체 그래프를 비교하여 스택 오버플로를 얻지는 않습니다.

0

그냥

또한, 모든 재귀 해제에 반복 스택을 사용 할 수 있습니다 ... 예를 들어 List<object> (또는 Set<> 또는 아무것도 같은)에, 당신은 이미 방문한 객체를 추적 당신이거야 수동으로 제어.

관련 문제