C# 递归查找所有DateTime对象
在我的mvc项目中,我设置了一个动作过滤器,它接受模型,遍历对象图并修改所有的日期时间对象。我的当前代码(在最后一个else块中)正在引发stackoverflow异常 我的模型中的一个属性是带有导航属性的EF对象,这应该忽略没有值或是基元、字符串、枚举等的属性。基本上是任何没有datetime子属性的类型C# 递归查找所有DateTime对象,c#,reflection,C#,Reflection,在我的mvc项目中,我设置了一个动作过滤器,它接受模型,遍历对象图并修改所有的日期时间对象。我的当前代码(在最后一个else块中)正在引发stackoverflow异常 我的模型中的一个属性是带有导航属性的EF对象,这应该忽略没有值或是基元、字符串、枚举等的属性。基本上是任何没有datetime子属性的类型 private void ProcessDateTimeProperties(object obj, ActionExecutedContext filterContext)
private void ProcessDateTimeProperties(object obj, ActionExecutedContext filterContext)
{
var properties = obj.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
foreach (var property in properties)
{
var t = property.PropertyType;
if (t.IsPrimitive || t == typeof(string) || t == typeof(Enum))
continue;
var p = property;
if (p.PropertyType == typeof(DateTime))
{
var date = (DateTime)p.GetValue(obj, null);
date.AddMinutes((int)filterContext.HttpContext.Cache["offset"]);
p.SetValue(obj, date, null);
}
// Same check for nullable DateTime.
else if (p.PropertyType == typeof(Nullable<DateTime>))
{
var date = (DateTime?)p.GetValue(obj, null);
if (!date.HasValue) continue; ;
date.Value.AddMinutes((int)filterContext.HttpContext.Cache["offset"]);
p.SetValue(obj, date, null);
}
else
{
var v = property.GetValue(obj, null);
if (v != null)
ProcessDateTimeProperties(v, filterContext);
}
}
}
private void ProcessDateTimeProperties(对象对象对象,ActionExecutedContext筛选器上下文)
{
var properties=obj.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
foreach(属性中的var属性)
{
var t=property.PropertyType;
if(t.IsPrimitive | | t==typeof(string)| | t==typeof(Enum))
继续;
var p=财产;
if(p.PropertyType==typeof(DateTime))
{
var date=(DateTime)p.GetValue(obj,null);
date.AddMinutes((int)filterContext.HttpContext.Cache[“offset”]);
p、 设置值(对象,日期,空);
}
//对可为空的DateTime进行相同的检查。
else if(p.PropertyType==typeof(可空))
{
var date=(DateTime?)p.GetValue(obj,null);
如果(!date.HasValue)继续;
date.Value.AddMinutes((int)filterContext.HttpContext.Cache[“offset”]);
p、 设置值(对象,日期,空);
}
其他的
{
var v=property.GetValue(obj,null);
如果(v!=null)
ProcessDateTimeProperties(v,filterContext);
}
}
}
您遇到的问题是循环引用
可以解决标记所有已检查的复杂对象的问题。像这样:
private void ProcessDateTimeProperties(object obj, ActionExecutedContext filterContext, HashSet<object> processedObjects = null)
{
if (processedObjects == null)
processedObjects = new HashSet<object>();
if (processObjects.Contains(obj))
return;
processedObjects.Add(obj);
var properties = obj.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
foreach (var property in properties)
{
var t = property.PropertyType;
if (t.IsPrimitive || t == typeof(string) || t == typeof(Enum))
continue;
var p = property;
if (p.PropertyType == typeof(DateTime))
{
var date = (DateTime)p.GetValue(obj, null);
date.AddMinutes((int)filterContext.HttpContext.Cache["offset"]);
p.SetValue(obj, date, null);
}
// Same check for nullable DateTime.
else if (p.PropertyType == typeof(Nullable))
{
var date = (DateTime?)p.GetValue(obj, null);
if (!date.HasValue) continue; ;
date.Value.AddMinutes((int)filterContext.HttpContext.Cache["offset"]);
p.SetValue(obj, date, null);
}
else
{
var v = property.GetValue(obj, null);
if (v != null)
ProcessDateTimeProperties(v, filterContext, processedObjects);
}
}
}
私有void ProcessDateTimeProperties(对象obj、ActionExecutedContext筛选器上下文、HashSet processedObjects=null)
{
if(processedObject==null)
processedObjects=newHashSet();
if(processObjects.Contains(obj))
返回;
processedObjects.Add(obj);
var properties=obj.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
foreach(属性中的var属性)
{
var t=property.PropertyType;
if(t.IsPrimitive | | t==typeof(string)| | t==typeof(Enum))
继续;
var p=财产;
if(p.PropertyType==typeof(DateTime))
{
var date=(DateTime)p.GetValue(obj,null);
date.AddMinutes((int)filterContext.HttpContext.Cache[“offset”]);
p、 设置值(对象,日期,空);
}
//对可为空的DateTime进行相同的检查。
else if(p.PropertyType==typeof(可空))
{
var date=(DateTime?)p.GetValue(obj,null);
如果(!date.HasValue)继续;
date.Value.AddMinutes((int)filterContext.HttpContext.Cache[“offset”]);
p、 设置值(对象,日期,空);
}
其他的
{
var v=property.GetValue(obj,null);
如果(v!=null)
ProcessDateTimeProperties(v、filterContext、ProcessedObject);
}
}
}
如您所见,我正在向函数添加processedObjects
可选参数,以标记已传递给递归函数的对象
调用函数时,不必传递此参数,它将在函数内部创建并递归传递
希望这有帮助。堆栈有多深?如果你有很多财产,这是可能的。如果是这样的话,与其递归使用while循环,不如使用stack循环,我认为在3或4层深度处将其切断是安全的。如果有一种方法可以排除null、原语、字符串、枚举等属性,那么应该考虑太多级别的情况。请记住,这是一个视图模型,我不可能有一个参数为另一个对象有5层深的对象。你有任何循环引用吗<代码>ObjA引用了
ObjB
哪些引用了ObjA
。甚至更长的周期,如A->B->C->D->A
。这肯定会导致堆栈溢出。跟踪您已经访问过的对象可能是值得的,这样您在访问之前就不会陷入循环。听起来这很快就会变得一团糟:(这很有效:如果(t.Module.ScopeName==“CommonLanguageUntimeLibrary”&&(t!=typeof(DateTime)&&t!=typeof(DateTime?)继续;