嵌套泛型类的递归

时间:2016-05-19 12:22:02

标签: c# generics

我有一个问题。 假设我有一个Generic类,它可以具有其他类的泛型属性,甚至可以有其他类的列表。 如果我有像

这样的功能
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>();

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

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

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

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

2 个答案:

答案 0 :(得分: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的检查以检查作为对象的属性。 / p>

答案 1 :(得分:1)

如果属性值是字符串,则可以直接设置该属性值,否则可以返回类似于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;
}