简体   繁体   English

如何遍历对象的嵌套属性

[英]How to iterate through nested properties of an object

I am trying to loop through all properties in an object including nested objects and objects in collections, to check if the property is of DateTime data type.我试图遍历对象中的所有属性,包括嵌套对象和集合中的对象,以检查该属性是否为 DateTime 数据类型。 If it is, convert the value to UTC time leaving everything intact including the structure and the value of other properties untouched.如果是,请将值转换为 UTC 时间,保持所有内容完好无损,包括结构和其他属性的值不变。 The structure of my classes as follows:我的类的结构如下:

public class Custom1 {
    public int Id { get; set; }
    public DateTime? ExpiryDate { get; set; }
    public string Remark { get; set; }
    public Custom2 obj2 { get; set; }
}

public class Custom2 {
    public int Id { get; set; }
    public string Name { get; set; }
    public Custom3 obj3 { get; set; }
}

public class Custom3 {
    public int Id { get; set; }
    public DateTime DOB { get; set; }
    public IEnumerable<Custom1> obj1Collection { get; set; }
}

public static void Main() {
    Custom1 obj1 = GetCopyFromRepository<Custom1>();

    // this only loops through the properties of Custom1 but doesn't go into properties in Custom2 and Custom3
    var myType = typeof(Custom1);
    foreach (var property in myType.GetProperties()) {
        // ...
    }
}

How do I loop through the properties in obj1 and traverse further down obj2 then obj3 then obj1Collection ?如何在OBJ1通过属性我环路和导线的进一步下跌OBJ2,然后再OBJ 3 obj1Collection? The function have to be generic enough because the Type passed to the function cannot be determined at design/compile time.该函数必须足够通用,因为在设计/编译时无法确定传递给函数的类型。 Conditional statements to test for Types should be avoided since they might be class Custom100应该避免测试类型的条件语句,因为它们可能是类Custom100

//avoid conditional statements like this
if (obj is Custom1) {
    //do something
} else if (obj is Custom2) {
    //do something else
}  else if (obj is Custom3) {
    //do something else
} else if ......

This is not a complete answer but I would start from here. 这不是一个完整的答案,但我将从这里开始。

var myType = typeof(Custom1);
            ReadPropertiesRecursive(myType);


private static void ReadPropertiesRecursive(Type type)
        {
            foreach (PropertyInfo property in type.GetProperties())
            {
                if (property.PropertyType == typeof(DateTime) || property.PropertyType == typeof(DateTime?))
                {
                    Console.WriteLine("test");
                }
                if (property.PropertyType.IsClass)
                {
                    ReadPropertiesRecursive(property.PropertyType);
                }
            }
        }

Check myType and if IsClass is true, then traverse into it. 检查myType,如果IsClass为true,则遍历它。 You'll probably want to make this recursive. 您可能需要进行递归。

I think it's far from the original question but ReadPropertiesRecursive above fall in infinite loop on 我认为这与原始问题相去甚远,但上面的ReadPropertiesRecursive陷入了无限循环

class Chain { public Chain Next { get; set; } }

I'd rather propose version with accumulation 我宁愿提出积累的版本

private static void ReadPropertiesRecursive(Type type, IEnumerable<Type> visited)
{
    foreach (PropertyInfo property in type.GetProperties())
    {
        if (property.PropertyType == typeof(DateTime) || property.PropertyType == typeof(DateTime?))
        {
            Console.WriteLine("test");
        }
        else if (property.PropertyType.IsClass && !visited.Contains(property.PropertyType))
        {
            ReadPropertiesRecursive(property.PropertyType, visited.Union(new Type[] { property.PropertyType }));
        }
    }
}
public static class ReadPropertiesExtension
{
    public static void ReadPropertiesRecursive<T>(object value, Func<T, T> func)
    {
        if (value is null)
            return;

        if (value is IEnumerable)
        {
            IList collection = (IList)value;
            foreach (var val in collection)
                ReadPropertiesRecursive(val, func);
            return;
        }

        var type = value.GetType();

        foreach (PropertyInfo property in type.GetProperties())
        {
            if (property.PropertyType == type)
                continue;
            if (!property.CanRead)
                continue;
            var val = property.GetValue(value);
            if (property.CanWrite && val is T param)
            {
                property.SetValue(value, func(param));
            }
            else if (property.PropertyType.IsClass && property.PropertyType != typeof(string))
            {
                ReadPropertiesRecursive(val, func);
            }
        }
    }
}

Here is a recursive function which also supports Enumerables.这是一个递归函数,它也支持枚举。 It takes a parameter func and executes this method anticipating that func takes parameter T and returns same param.它接受一个参数 func 并执行此方法,预计 func 接受参数 T 并返回相同的参数。 You can call it like- ReadPropertiesExtension.ReadPropertiesRecursive<double>(value, func1);你可以这样称呼它 - ReadPropertiesExtension.ReadPropertiesRecursive<double>(value, func1);

Note: Currently, it doesn't support objects which contain dictionary in it.注意:目前,它不支持包含字典的对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM