如何在.Net中迭代类的子级

本文关键字:迭代 Net | 更新日期: 2023-09-27 18:21:22

我有一个C#.Net类RootObject,它包含许多不同对象类型的列表。我从ajax调用中获得一个json对象,并将其反序列化为一个RootObject实例。我想遍历根对象中的所有列表,并为它们创建数据表以传递给存储过程,但我不知道如何做到这一点。有人能帮忙吗?

public class RootObject
{
    public List<Car> Car { get; set;}
    public List<Plane> Plane { get; set;}
    public List<Train> Train { get; set;}
}
    /// <summary>
    /// Returns a data table filled with the values from the input list
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="list"></param>
    /// <returns></returns>
    public DataTable CreateDataTable<T>(IEnumerable<T> list)
    {
        Type type = typeof(T);
        var properties = type.GetProperties();
        DataTable dataTable = new DataTable();
        foreach (PropertyInfo info in properties)
        {
            dataTable.Columns.Add(new DataColumn(info.Name, Nullable.GetUnderlyingType(info.PropertyType) ?? info.PropertyType));
        }
        foreach (T entity in list)
        {
            object[] values = new object[properties.Length];
            for (int i = 0; i < properties.Length; i++)
            {
                values[i] = properties[i].GetValue(entity);
            }
            dataTable.Rows.Add(values);
        }
        return dataTable;
    }

    /// <summary>
    /// This function saves the layout specified by the the user with the ID specified
    /// </summary>
    /// <param name="encryptedBEMSID"></param>
    /// <param name="Layout"></param>
    /// <returns></returns>
    public string Save(string encryptedBEMSID, string Layout)
    {
        // Make a list of table variable parameters to hold the results of the deserialization
        List<SqlParameter> parameters = new List<SqlParameter>();
        // Deserialize the json object
        RootObject obj = JsonConvert.DeserializeObject<RootObject>(Layout);
        PropertyInfo[] objLists = obj.GetType().GetProperties();
        foreach (PropertyInfo pi in objLists)
        {
            string ObjectType = pi.Name; // This would be "Car", "Plane", or "Train"
            string UpperObjectType = ObjectType.ToUpper();
// HERE'S WHERE I NEED HELP! I'd Like to replace Car with the class specified by ObjectType 
            List<Car> List = obj.Car;
            DataTable dt = CreateDataTable<Car>(List);
            // do stuff with the resulting data table
        }
    }

编辑以添加JSON

{
    "Car": [
        {"name": "The General", "color": "red"},
        {"name": "Batmobile", "color": "blue"}
    ],
    "Plane": [
        {"name": "Air Force One", "color": "white"},
        {"name": "Spirit of St. Louis", "color": "gray"},
        {"name": "Wright Flyer", "color": "brown"}
    ],
    "Train": [
        {"name": "Orient Express", "color": "black"},
        {"name": "Ye Olde Bullet Train", "color": "orange"}
    ]
}

如何在.Net中迭代类的子级

foreach(var vehicle in vehicles) { //iterate car, plane, train
    foreach(var instance in vehicle) { //iterate the general, batmobile, etc.
        /* do stuff */
    }
}

假设您的对象只是{name,color},您可以为此创建一个类,例如Vehicle,然后反序列化为Dictionary<string,List<Vehicle>>

现在,您可以轻松地枚举字典,并从每个键中枚举车辆列表。

如果它比您展示的JSON更复杂,那么您最好直接读取JSON(使用JSON.NET)并以这种方式处理它。

您还可以在JSON中添加一个类型鉴别器(请参阅https://www.mallibone.com/post/serialize-object-inheritance-with-json.net)然后Json.NET将知道CCD_ 3字段包含CCD_。您还可以提供一个自定义序列化绑定器,用于处理由字段名定义的类型的特殊情况。您仍然需要一个基类Vehicle,但实际的反序列化值将是预期的类型。

另外,另一种选择可能是使用Dictionary<string, Dictionary<string, object>>来保存反序列化的JSON,因为您所做的只是将值复制到表中——您不在乎它是Car,它只是名称和值的集合。

如果将数据表创建转移到泛型类VehicleHandler<T>中,则可以创建一个与当前检查的属性类型匹配的类型T的实例,如下所示:-

Type vehicleListType = pi.PropertyType;
Type vehicleType = vehicleListType.GetGenericArguments()[0];
var vehicleHandlerType = typeof (VehicleHandler<>).MakeGenericType(vehicleType);
var vehicleHandler = (VehicleHandler)Activator.CreateInstance(vehicleHandlerType);

现在,您可以为该字段设置车辆并生成数据表:

vehicleHandler.SetVehicles(pi.GetValue(obj));
var dataTable = vehicleHandler.DataTable;

VehicleHandler的代码是:

public abstract class VehicleHandler
{
    public abstract void SetVehicles(object listOfVehicles);
    public abstract DataTable DataTable { get; }
}
public class VehicleHandler<T> : VehicleHandler
{
    List<T> vehicles;
    public override void SetVehicles (object listOfVehicles)
    {
        this.vehicles = (List<T>) listOfVehicles;
    }
    public override DataTable DataTable => CreateDataTable(vehicles);
    public DataTable CreateDataTable(IEnumerable<T> list)
    {
        Type type = typeof (T);
        var properties = type.GetProperties();
        DataTable dataTable = new DataTable();
        foreach (PropertyInfo info in properties)
        {
            dataTable.Columns.Add(new DataColumn(info.Name,
                Nullable.GetUnderlyingType(info.PropertyType) ?? info.PropertyType));
        }
        foreach (T entity in list)
        {
            object[] values = new object[properties.Length];
            for (int i = 0; i < properties.Length; i++)
            {
                values[i] = properties[i].GetValue(entity);
            }
            dataTable.Rows.Add(values);
        }
        return dataTable;
    }
}