【问题标题】:Recursion on nested Generic classes嵌套泛型类的递归
【发布时间】:2016-05-19 20:45:35
【问题描述】:

我有一个问题。 假设我有一个通用类,它可以具有其他类的通用属性,甚至可以具有其他类的列表。 如果我有这样的功能

public void Read<T>() where T: class, new() 
{

    // Create an instance of our generic class
    var model = new T();
    var properties = typeof(T).GetProperties();

    // Loop through the objects properties
    for(var property in properties) {

        // Set our value
        SetPropertyValue(property, model, "test");
    }
}

private void SetPropertyValue(PropertyInfo property, object model, string value) {

    // Set our property value
    property.SetValue(model, value, null);
}

如果我有这样的课程,那就行了:

public class Person
{
    public string Name { get; set; }
}

我像这样调用 Read 方法:

Read<Person>();

但如果我的 Person 模型是这样的:

public class Person
{
    public string Name { get; set; }
    public Company Company { get; set; }
}

public class Company 
{
    public string Name { get; set; }
}

我尝试再次调用 Read 方法,因为该属性有它自己的属性列表,所以它会失败。 如果它也穿过它们会更好。有没有办法做到这一点?

【问题讨论】:

  • 除了泛型之外,只需实现非泛型版本的 Read 方法。从泛型 - 调用非泛型版本不要过多重复代码。然后当你递归时 - 只需调用具有属性类型的非通用版本。无论如何,非通用版本通常都很好。

标签: c# generics


【解决方案1】:

这个answer 可以提供帮助。 你应该以这样的方式结束:

if (t.IsPrimitive || t == typeof(Decimal) || t == typeof(String) || ... )
    SetPropertyValue(property, model, "test");
else
    // You will have to recode this line,
    // it's just to show you the idea how you can work around
    SetPropertyValue(property, model, Read.MakeGeneric(property.Type)());

您还需要从 Read 方法中返回模型变量。

条件取决于您要覆盖的类型,如果像您的示例一样,您可以将条件更改为仅匹配字符串并在 else 上添加检查以检查对象属性。

【讨论】:

    【解决方案2】:

    如果是字符串可以直接设置属性值,否则可以返回类似于Read的方法的值,以Type为参数创建模型并递归填充其属性。

    public void Read<T>() where T : class, new()
    {
        // Create an instance of our generic class
        var model = new T();
        var properties = typeof(T).GetProperties();
    
        // Loop through the objects properties
        foreach(var property in properties)
        {
            // Set our value
            SetPropertyValue(property, model, "test");
        }
    }
    
    private void SetPropertyValue(PropertyInfo property, object model, string value)
    {
        if (property.PropertyType == typeof(string))
        {
            // Set our property value
            property.SetValue(model, value, null);
        }
        else
        {
            var submodel = Read(property.PropertyType);
            property.SetValue(model, submodel, null);
        }
    }
    
    private object Read(Type type)
    {
        if (!IsTypeSupported(type))
        {
            throw new ArgumentException();
        }
    
        var model = type.GetConstructor(new Type[0]).Invoke(new object[0]);
        var properties = type.GetProperties();
    
        foreach (var property in properties)
        {
            SetPropertyValue(property, model, "test");
        }
    
        return model;
    }
    
    private bool IsTypeSupported(Type type)
    {
        return type.IsClass && type.GetConstructor(new Type[0]) != null;
    }
    

    【讨论】:

    • 当然,这是假设 OP 不必处理其他原始类型,例如 intdouble
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-11-02
    • 1970-01-01
    • 1970-01-01
    • 2021-12-05
    • 1970-01-01
    • 2010-10-23
    • 1970-01-01
    相关资源
    最近更新 更多