【问题标题】:recursively create custom complex object递归创建自定义复杂对象
【发布时间】:2015-05-03 02:37:53
【问题描述】:

我想递归地构建一个复杂的对象。

public class Name
{
   public string firstName {get;set;}
   public string lastName {get;set;}
}

public class Address
{
   public string city {get;set;}
   public string state {get;set;}
   public string street {get;set;}
   public string zip {get;set;}
}

public class Customer
{
   public Name customerName {get;set;}
   public Address customerAddress {get;set;}
   public Guid id {get;set;}
}

假设客户生活在我正在加载的程序集中:) 我想实例化一种客户并填充其属性。 Customer 对象有更多的自定义对象和一个 Guid 属性。如何使用递归来创建 Customer 对象及其嵌套对象。我在下面有一些代码,我偶然发现我应该使用递归。

static object TraversePropertyInfo(object obj, Assembly assembly)
    {
        Console.WriteLine(obj.GetType().Name);

        foreach(PropertyInfo pi in obj.GetType().GetProperties())
        {
            if(pi.PropertyType.IsClass && pi.PropertyType.Namespace != "System")
            {
                if(pi.PropertyType.UnderlyingSystemType.GenericTypeArguments.Count() > 0)
                {
                    Console.WriteLine("\tIList<{0}>", pi.Name);
                }
                else
                {
                    Console.WriteLine("\t{0}\t<class>", pi.Name);
                    object child = Activator.CreateInstance(assembly.GetType(pi.PropertyType.FullName));  // create the child instance
                    obj.GetType().GetProperty(pi.Name).SetValue(obj, child);                              // set the child on the parent
                    // but the child can have children...
                    // I should be using recurrsion here 
                }
            }
            else
            {
                Console.WriteLine("\t{0}\t{1}", pi.Name, pi.PropertyType);
            }
        }
        return obj;
    }

【问题讨论】:

  • 是否有任何类具有接受参数的构造函数?
  • 没有一个类有带参数的构造函数

标签: c# .net generics recursion reflection


【解决方案1】:
void Main()
{
    Create<Customer>().Dump();
}

// Define other methods and classes here

public class Name
{
   public string Firstname { get; set; }
   public string Lastname { get; set; }
}

public class Address
{
   public string City { get; set; }
   public string State { get; set; }
   public string Street { get; set; }
   public string Zip { get; set; }
}

public class Customer
{
   public Name CustomerName { get; set; }
   public Address CustomerAddress { get; set; }
   public Guid Id { get; set; }
}

public static T Create<T>()
{
    var type = typeof(T);

    return (T)Create(type);
}

public static object Create(Type type)
{
    var obj = Activator.CreateInstance(type);

    foreach(var property in type.GetProperties())
    {
        var propertyType = property.PropertyType;

        if (propertyType.IsClass 
            && string.IsNullOrEmpty(propertyType.Namespace)
            || (!propertyType.Namespace.Equals("System") 
                && !propertyType.Namespace.StartsWith("System.")))
        {
            var child = Create(propertyType);

            property.SetValue(obj, child);
        }
    }

    return obj;
}

【讨论】:

    【解决方案2】:

    也许这会起作用:

    static object TraversePropertyInfo(object obj, Assembly assembly)
    {
        Console.WriteLine(obj.GetType().Name);
        // we stop the iteration when we reached the root-class "object" 
        // which won´t add any custom properties
        if (obj.GetType() == typeof(object) return obj;
    
    
        foreach(PropertyInfo pi in obj.GetType().GetProperties())
        {
            if(pi.PropertyType.IsClass && pi.PropertyType.Namespace != "System")
            {
                if(pi.PropertyType.UnderlyingSystemType.GenericTypeArguments.Count() > 0)
                {
                    Console.WriteLine("\tIList<{0}>", pi.Name);
                }
                else
                {
                    Console.WriteLine("\t{0}\t<class>", pi.Name);
                    object child = Activator.CreateInstance(assembly.GetType(pi.PropertyType.FullName));  // create the child instance
                    child = TraversePropertyInfo(child, child.GetType().Assembly);
                    obj.GetType().GetProperty(pi.Name).SetValue(obj, child);                              // set the child on the parent
                    // this will do the recursion
                    return obj;
                }
            }
            else
            {
                Console.WriteLine("\t{0}\t{1}", pi.Name, pi.PropertyType);
            }
        }
        return obj;
    }
    

    【讨论】:

    • 在 foreach 循环内返回会覆盖原始对象并在我遍历所有对象之前返回。 :(
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-25
    • 1970-01-01
    • 2017-11-20
    • 1970-01-01
    • 2012-06-26
    • 2020-06-28
    • 2022-11-23
    相关资源
    最近更新 更多