在我的mvc项目中,我整理了一个动作过滤器,它接受模型,遍历对象图并修改所有日期时间对象。我当前的代码(在最后一个else块中)抛出了stackoverflow异常。
我的模型中的一个属性是具有导航属性的EF对象,这应该忽略没有值的属性或者是基元,字符串,枚举等。基本上任何没有子属性的类型日期时间。
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);
}
}
}
答案 0 :(得分:1)
你遇到的问题是循环参考。
您可以解决标记已检查的所有复杂对象的问题。像这样:
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);
}
}
}
正如您所看到的,我将processedObjects
可选参数添加到函数中以标记已传递给递归函数的对象。
当您调用该函数时,您不必传递此参数,它将在函数内部创建并递归传递。
希望这有帮助。