C# 实例化包含所有对象属性的类型实例,并遵守继承

C# 实例化包含所有对象属性的类型实例,并遵守继承,c#,reflection,json.net,C#,Reflection,Json.net,我不确定这个标题是否反映了实际问题,所以让我解释一下。有没有一种方法可以实例化一个类并递归实例化所有属于类的属性 例如: public class Base { public int BaseValue{ get; set;} } public class Extended : Base { public int ExtendedValue{ get; set;} public AnotherExtendedClass AnotherClass { get; set;

我不确定这个标题是否反映了实际问题,所以让我解释一下。有没有一种方法可以实例化一个类并递归实例化所有属于类的属性

例如:

public class Base
{
    public int BaseValue{ get; set;} 
}

public class Extended : Base
{
    public int ExtendedValue{ get; set;}
    public AnotherExtendedClass AnotherClass { get; set;}
}
我想创建一个json负载,它由一个
Extended
的空实例组成,并实例化所有默认值和属性。然后像这样使用它:

string representation = Test.CreateDefaultEmptyJson(Extended);

public static string CreateDefaultEmptyJson(Type type)
{
    JsonSerializerSettings settings = new JsonSerializerSettings().Configure();
    var defaultInstance= Activator.CreateInstance(type);
    return JsonConvert.SerializeObject(defaultInstance, settings);
}
输出不包括
扩展的
类属性。我回来了:

{
    "BaseValue":0
}
当我真的想看(或类似的东西)的时候:


我想我可以递归地迭代所有类型的
Extended
,并调用默认构造函数,然而,在我继续这条路之前,可能会有几行代码来完成相同的任务。

这个匆忙编写的类开始解决您的问题。它返回可设置的属性,这些属性返回引用类型并递归遍历它们,根据需要创建实例

它不包括

  • 索引属性
  • 递归深度
您最好只设置属性本身的默认值,这样类就不会被创建为不需要的空值

public class PropertyPopulator
{
    public void PopulateProperties(object target)
    {
        var properties = target.GetType()
            .GetProperties(BindingFlags.Instance | BindingFlags.Public)
            .Where(p => p.PropertyType.IsClass && p.CanWrite && p.CanRead);
        foreach (var property in properties)
        {
            var propertyValue = property.GetValue(target);
            if (propertyValue == null)
            {
                var constructor = property.PropertyType.GetConstructor(new Type[] { });
                if (constructor != null)
                {
                    propertyValue = constructor.Invoke(new object[] { });
                    property.SetValue(target, propertyValue);
                    PopulateProperties(propertyValue);
                }
            }
        }
    }
}

这节仓促编写的课开始解决你的问题。它返回可设置的属性,这些属性返回引用类型并递归遍历它们,根据需要创建实例

它不包括

  • 索引属性
  • 递归深度
您最好只设置属性本身的默认值,这样类就不会被创建为不需要的空值

public class PropertyPopulator
{
    public void PopulateProperties(object target)
    {
        var properties = target.GetType()
            .GetProperties(BindingFlags.Instance | BindingFlags.Public)
            .Where(p => p.PropertyType.IsClass && p.CanWrite && p.CanRead);
        foreach (var property in properties)
        {
            var propertyValue = property.GetValue(target);
            if (propertyValue == null)
            {
                var constructor = property.PropertyType.GetConstructor(new Type[] { });
                if (constructor != null)
                {
                    propertyValue = constructor.Invoke(new object[] { });
                    property.SetValue(target, propertyValue);
                    PopulateProperties(propertyValue);
                }
            }
        }
    }
}

据我所知,除了编写自己的递归方法之外,没有一种内置的方法来实现这一点。
但是,假设:

  • 您的类都有无参数(默认)构造函数
  • 非基本属性都是具体类型(不是接口),并且
  • 在类结构中没有任何引用循环
  • 然后,您可以用十几行代码创建这样一个方法:

    public static string CreateDefaultEmptyJson(Type type)
    {
        return JsonConvert.SerializeObject(RecursiveCreateInstance(type), Formatting.Indented);
    }
    
    public static object RecursiveCreateInstance(Type type)
    {
        object obj = null;
        ConstructorInfo ctor = type.GetConstructor(Type.EmptyTypes);
        if (ctor != null)
        {
            obj = ctor.Invoke(null);
            foreach (PropertyInfo prop in type.GetProperties())
            {
                Type propType = prop.PropertyType;
                if (prop.CanWrite && propType.IsClass)
                {
                    prop.SetValue(obj, RecursiveCreateInstance(propType));
                }
            }
        }
        return obj;
    }
    
    小提琴:


    如果上述假设不成立,那么事情很快就会变得复杂。如果您遇到了一些问题,需要一种简单的方法来创建假对象以进行测试,那么您可能需要考虑使用。

    据我所知,除了编写自己的递归方法之外,没有一种内置的方法来实现这一点。
    但是,假设:

  • 您的类都有无参数(默认)构造函数
  • 非基本属性都是具体类型(不是接口),并且
  • 在类结构中没有任何引用循环
  • 然后,您可以用十几行代码创建这样一个方法:

    public static string CreateDefaultEmptyJson(Type type)
    {
        return JsonConvert.SerializeObject(RecursiveCreateInstance(type), Formatting.Indented);
    }
    
    public static object RecursiveCreateInstance(Type type)
    {
        object obj = null;
        ConstructorInfo ctor = type.GetConstructor(Type.EmptyTypes);
        if (ctor != null)
        {
            obj = ctor.Invoke(null);
            foreach (PropertyInfo prop in type.GetProperties())
            {
                Type propType = prop.PropertyType;
                if (prop.CanWrite && propType.IsClass)
                {
                    prop.SetValue(obj, RecursiveCreateInstance(propType));
                }
            }
        }
        return obj;
    }
    
    小提琴:


    如果上述假设不成立,那么事情很快就会变得复杂。如果您遇到一些问题,需要一种简单的方法来创建用于测试目的的假对象,那么您可能需要考虑使用。

    我的回答也忽略了问题的一个要求。您希望实例化一个对象,而不是从一个实例开始并根据需要填充属性。但在这种情况下,我仍然倾向于设置属性的默认值,以便它们一开始不为null。然后你只需要创建一个基类型的新实例,其余的就可以了。您希望实例化一个对象,而不是从一个实例开始并根据需要填充属性。但在这种情况下,我仍然倾向于设置属性的默认值,以便它们一开始不为null。然后,您只需创建一个基类型的新实例,其余的将自行处理。