C# 在c中通过反射在对象内部爬行时防止堆栈溢出#

C# 在c中通过反射在对象内部爬行时防止堆栈溢出#,c#,reflection,recursion,stack-overflow,C#,Reflection,Recursion,Stack Overflow,我有一个叫做MatchNodes的方法:IEnumerable MatchNodes(tn1,tn2) 它基本上从T对象中获取每个属性和字段(通过反射,不包括基类中的属性/字段),并对它们进行比较,将结果作为布尔的IEnumerable返回 当它找到一个基元类型或字符串时,if只返回它们之间的= 当它找到从集合派生的类型时,它迭代每个成员并为每个成员调用MatchNodes(哎哟) 当它找到任何其他类型时,会为每个属性/字段调用MatchNodes 我的解决方案显然是要求出现堆栈溢出异常,但我不

我有一个叫做MatchNodes的方法:
IEnumerable MatchNodes(tn1,tn2)

它基本上从
T
对象中获取每个属性和字段(通过反射,不包括基类中的属性/字段),并对它们进行比较,将结果作为布尔的IEnumerable返回

当它找到一个基元类型或字符串时,if只返回它们之间的
=

当它找到从集合派生的类型时,它迭代每个成员并为每个成员调用
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;
        }

    }
公共静态IEnumerable匹配节点(tn1,tn2)
{
Func Func=null;
if(typeof(T)=typeof(String))
{
字符串str1=n1作为字符串;
字符串str2=n2作为字符串;
func=新func((属性)=>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=新func((属性)=>
{
foreach(e1中的var v1)
{
if(e2.GetEnumerator().MoveNext())
{
var v2=e2.GetEnumerator().Current;
if(((IEnumerable)MatchNodes(v1,v2)).All(b=>b==true))
{
返回false;
}
}
其他的
{
返回false;
}
}
if(e2.GetEnumerator().MoveNext())
{
返回false;
}
否则返回true;
});
}
else if(typeof(T).IsPrimitive | | typeof(T)=typeof(Decimal))
{
func=newfunc((property)=>property.GetValue(n1,null)==property.GetValue(n2,null));
}
其他的
{
func=新func((属性)=>
((IEnumerable)匹配节点(property.GetValue(n1,null),
GetValue(n2,null)).All(b=>b==true));
}
foreach(typeof(T).GetProperties()中的PropertyInfo属性,其中((property)=>property.DeclaringType==typeof(T)))
{
布尔结果=func(属性);
收益结果;
}
}
我看到的是一种无需递归调用我的方法就可以爬行到对象中的方法

编辑

举例说明:

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;}
}
公共类Class1:RandomClassWithMoreProperties{
公共字符串Str1{get;set;}
公共int Int1{get;set;}
}
公共课2{
公共列表MyClassProp1{get;set;}
公共类1 MyClassProp2{get;set;}
公共字符串MyStr{get;set;}
}
MatchNodes(n1,n2)
其中
n1.GetType()
n2.GetType()
Class2
如果:

  • MyClassProp1
    中的每个
    Class1
    对象对于这两个对象都具有相同的
    Str1
    Int1
  • MyClassProp2
    对于这两个对象都具有相同的
    Str1
    Int1
  • MyStr
    对于两个对象都是相等的

我不会将
随机类中的任何属性与更多属性进行比较

这里的一个好方法是保留您接触过的对象的痕迹,并在深入研究时向前传递。对于每个新对象,检查它是否在您已经看到的对象图中,如果是,则短路并退出(您已经看到该节点)。堆栈可能是合适的


通过比较一个非循环对象图,你不太可能得到堆栈溢出-当你以循环结束时,事情就会爆炸。

一个好的方法是保留你接触过的对象的痕迹,并在你深入研究时向前传递。对于每个新对象,检查它是否在您已经看到的对象图中,如果是,则短路并退出(您已经看到该节点)。堆栈可能是合适的


通过比较一个非循环对象图,你不太可能得到堆栈溢出-当你以循环结束时,事情就会爆炸。

只需跟踪你已经访问过的对象,例如,在
列表中(或
集合
或类似的东西)


此外,任何递归都可以使用手动控制的堆栈取消递归。

只需跟踪您已经访问过的对象,例如在
列表中(或
设置
或类似的内容)


此外,任何递归都可以使用手动控制的堆栈取消递归。

您可以使用堆栈或队列存储要比较的属性。大致是这样的:

 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
 }
var stack=newstack();
//给堆栈加底漆
foreach(n1.GetType().GetProperties()中的var prop)
{
stack.Push(Tuple.Create(prop.GetValue(n1)、prop.GetValue(n2));
}
而(stack.Count>0)
{
var current=stack.Pop();
//如果当前为promitive:比较
//如果当前可枚举:将所有元素作为元组推送到堆栈上
//else:将所有属性作为元组推送到堆栈上
}
如果您使用
队列
而不是
堆栈
,您将获得BFS而不是DFS。此外,您可能还应该跟踪alre