如何将具有嵌入对象的对象List转换为DataTable

时间:2013-12-27 00:04:23

标签: c# object datatable

例如,如果我有一个UserType类的User类,如下所示:

public class User
{
    public int   UserID                {get; set;}
    public string   UserName           {get; set;}
    public string    DisplayName       {get; set;}
    public UserType  UserType          {get; set;}
 }

public class UserType
{
    public int  UserTypeID          {get; set;} 
    public string   Name            {get; set;}
    public string   Description     {get; set;}
}

然后我想要一个将用户List转换为DataTable的方法。

List<User> Users = new List<User>();
DataTable dt = ConvertToDataTable(Users)

目前,我有一种方法可以将objectClass的List转换为DataTable,但是当它内部嵌入一个对象(UserType对象)时,转换将失败。是否有可能将List<User>转换为DataTable,而UserType中的字段的列名称为“UserType.Name”,“UserType.Description”

例如,通过将List<User>对象转换为DataTable,它将包含以下列:

  

UserID UserName DisplayName UserType.UserTypeID UserType.Name UserType.Description

根据您的请求,这是我用于将List转换为DataTable

的方法
        ///<summary> Convert List of Object to Data Table (To Display in Data Table).  </summary>
        public static DataTable From_Obj_Lst(object list)
        {
            DataTable   dt          = null;
            Type        listType    = list.GetType();
            if (listType.IsGenericType)
            {
                //Determine the underlying type the List<> contains 
                Type elementType = listType.GetGenericArguments()[0];

                //create empty table -- give it a name in case 
                //it needs to be serialized 
                dt = new DataTable(elementType.Name + "List");

                //define the table -- add a column for each public 
                //property or field 
                MemberInfo[] miArray = elementType.GetMembers(
                    BindingFlags.Public | BindingFlags.Instance);
                foreach (MemberInfo mi in miArray)
                {
                    if (mi.MemberType == MemberTypes.Property)
                    {
                        PropertyInfo pi = mi as PropertyInfo;
                        dt.Columns.Add(pi.Name, Nullable.GetUnderlyingType(pi.PropertyType) ?? pi.PropertyType);
                    }
                    else if (mi.MemberType == MemberTypes.Field)
                    {
                        FieldInfo fi = mi as FieldInfo;
                        dt.Columns.Add(fi.Name, fi.FieldType);
                    }
                }

                //populate the table 
                IList il = list as IList;
                foreach (object record in il)
                {
                    int i = 0;
                    object[] fieldValues = new object[dt.Columns.Count];
                    foreach (DataColumn c in dt.Columns)
                    {
                        MemberInfo mi = elementType.GetMember(c.ColumnName)[0];
                        if (mi.MemberType == MemberTypes.Property)
                        {
                            PropertyInfo pi = mi as PropertyInfo;
                            fieldValues[i] = pi.GetValue(record, null);
                        }
                        else if (mi.MemberType == MemberTypes.Field)
                        {
                            FieldInfo fi = mi as FieldInfo;
                            fieldValues[i] = fi.GetValue(record);
                        }
                        i++;
                    }
                    dt.Rows.Add(fieldValues);
                }
            }

            //Finally
            return dt;
        }

2 个答案:

答案 0 :(得分:1)

您需要的是转换器中的“PropertyInfo”,当您发现属性为int或string时,您可以直接获取该值,或者递归获取嵌入对象值。

PropertyInfo[] propList = obj.GetType().GetProperties(); //This will get all property with property name
foreach (PropertyInfo pInfo in propList)
{
    if (pInfo.PropertyType == typeof(int) || pInfo.PropertyType == typeof(string))
    {
        //Just get the value and insert to your table
        object propValue = pInfo.GetValue(obj, null); //Notice this is not fit for array type
    }
    else
    {
        //This is embeded object
        string thisPropName = pInfo.Name; //Get the property name. Here should be UserType
        object propValue = pInfo.GetValue(obj, null); //Then you can use this object to get its inside property name and value with same method above.
    }



}

答案 1 :(得分:0)

我喜欢你将一些类的List转换为DataTable的想法,我有一些情况可以使用这个函数。所以我有时候会让你的现有函数使用包含另一个对象/类的属性的对象。

public static DataTable From_Obj_Lst(object list)
{
    DataTable dt = null;
    Type listType = list.GetType();
    if (listType.IsGenericType)
    {
        Type elementType = listType.GetGenericArguments()[0];
        dt = new DataTable(elementType.Name + "List");

        AddColumns(ref dt, elementType, "");

        IList il = list as IList;
        foreach (object record in il)
        {
            int i = 0;
            object[] fieldValues = new object[dt.Columns.Count];
            foreach (DataColumn c in dt.Columns)
            {
                fieldValues[i] = GetValueByColumnName(c.ColumnName, record);
                i++;
            }
            dt.Rows.Add(fieldValues);
        }
    }
    return dt;
}

我移动了将列操作添加到另一个方法并应用了某种递归行为,因此如果属性类型为ClassA,则该方法会将其称为self,以便为ClassA中的每个属性添加列。由于该方法是递归的,因此当ClassA具有ClassB类型的属性,并且ClassB具有类型ClassC的属性等等时,我希望这可以正常工作 - < em>没有测试超过两个级别 - 。在这里,我使用属性名称作为列前缀而不是属性类型名称以避免重复的列名称,因此当对象具有两个具有相同类型的属性时,该函数将起作用。

public static void AddColumns(ref DataTable dt, Type elementType, string columnPrefix)
{
    MemberInfo[] miArray = elementType.GetMembers(
        BindingFlags.Public | BindingFlags.Instance);
    foreach (MemberInfo mi in miArray)
    {
        if (mi.MemberType == MemberTypes.Property)
        {
            PropertyInfo pi = mi as PropertyInfo;
            if (pi.PropertyType.IsPrimitive || pi.PropertyType == typeof(String))
                dt.Columns.Add(columnPrefix + pi.Name, Nullable.GetUnderlyingType(pi.PropertyType) ?? pi.PropertyType);
            else AddColumns(ref dt, pi.PropertyType, String.Format("{0}{1}.", columnPrefix, pi.Name));
        }
        else if (mi.MemberType == MemberTypes.Field)
        {
            FieldInfo fi = mi as FieldInfo;
            if (fi.FieldType.IsPrimitive || fi.FieldType == typeof(String))
                dt.Columns.Add(columnPrefix + fi.Name, fi.FieldType);
            else AddColumns(ref dt, fi.FieldType, String.Format("{0}{1}.", columnPrefix, fi.Name));
        }
    }
}

为行中的每一列获取值的逻辑与从属性添加列名称的逻辑相反。具有value = null的属性也可以正确处理 - 测试了这个 - 。

public static object GetValueByColumnName(string colName, object record)
{
    var isComplexProperty = colName.Split('.').Length > 1;
    if (!isComplexProperty)
    {
        return GetSimplePropertyValue(colName, record);
    }
    else
    {
        var propertyName = colName.Split('.')[0];
        var propertyValue = GetSimplePropertyValue(propertyName, record);
        if (propertyValue != null)
            return GetValueByColumnName(colName.Replace(propertyName + ".", ""), propertyValue);
    }
    return null;
}

public static object GetSimplePropertyValue(string propName, object record)
{
    Type elementType = record.GetType();
    MemberInfo mi = elementType.GetMember(propName)[0];
    if (mi.MemberType == MemberTypes.Property)
    {
        PropertyInfo pi = mi as PropertyInfo;
        return pi.GetValue(record, null);
    }
    else if (mi.MemberType == MemberTypes.Field)
    {
        FieldInfo fi = mi as FieldInfo;
        return fi.GetValue(record);
    }
    return null;
}