C# 嵌套泛型类上的递归

C# 嵌套泛型类上的递归,c#,generics,C#,Generics,我有个问题。 假设我有一个泛型类,它可以具有其他类的泛型属性,甚至可以具有其他类的列表。 如果我有一个函数 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 t

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

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);
}
我调用了Read方法,如下所示:

public class Person
{
    public string Name { get; set; }
}
Read<Person>();
public class Person
{
    public string Name { get; set; }
    public Company Company { get; set; }
}

public class Company 
{
    public string Name { get; set; }
}
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方法,它会失败,因为属性有自己的属性列表。 如果它也能穿过它们,那就更好了。有办法吗?

这会有帮助。 你应该这样结束:

public class Person
{
    public string Name { get; set; }
}
Read<Person>();
public class Person
{
    public string Name { get; set; }
    public Company Company { get; set; }
}

public class Company 
{
    public string Name { get; set; }
}
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上添加检查以检查对象属性。

如果是字符串,则可以直接设置属性值,否则,您可以返回类似于
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;
}
public void Read(),其中T:class,new()
{
//创建泛型类的实例
var模型=新T();
var properties=typeof(T).GetProperties();
//循环浏览对象属性
foreach(属性中的var属性)
{
//设定我们的价值
SetPropertyValue(属性、模型、“测试”);
}
}
私有void SetPropertyValue(PropertyInfo属性、对象模型、字符串值)
{
if(property.PropertyType==typeof(string))
{
//设定我们的财产价值
SetValue(model,value,null);
}
其他的
{
var子模型=读取(property.PropertyType);
SetValue(模型,子模型,null);
}
}
私有对象读取(类型)
{
如果(!IsTypeSupported(类型))
{
抛出新ArgumentException();
}
var model=type.GetConstructor(新类型[0]).Invoke(新对象[0]);
var properties=type.GetProperties();
foreach(属性中的var属性)
{
SetPropertyValue(属性、模型、“测试”);
}
收益模型;
}
支持私有布尔ISTYPE(类型)
{
返回type.IsClass&&type.GetConstructor(新类型[0])!=null;
}

只需实现Read方法的非泛型版本,以及泛型版本。从泛型-调用非泛型版本以避免代码重复过多。然后,当您递归时,只需使用属性类型调用非泛型版本。不管怎样,非泛型版本通常是很好的。当然,这是假设OP不必处理其他基本类型,如
int
double