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