C# 递归查找所有DateTime对象

C# 递归查找所有DateTime对象,c#,reflection,C#,Reflection,在我的mvc项目中,我设置了一个动作过滤器,它接受模型,遍历对象图并修改所有的日期时间对象。我的当前代码(在最后一个else块中)正在引发stackoverflow异常 我的模型中的一个属性是带有导航属性的EF对象,这应该忽略没有值或是基元、字符串、枚举等的属性。基本上是任何没有datetime子属性的类型 private void ProcessDateTimeProperties(object obj, ActionExecutedContext filterContext)

在我的mvc项目中,我设置了一个动作过滤器,它接受模型,遍历对象图并修改所有的日期时间对象。我的当前代码(在最后一个else块中)正在引发stackoverflow异常

我的模型中的一个属性是带有导航属性的EF对象,这应该忽略没有值或是基元、字符串、枚举等的属性。基本上是任何没有datetime子属性的类型

    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?)继续;