字段名为空space时,如何使用toList反序列化数据表?

How to use toList to deserialize datatable when there is a field name with empty space?

我有一个 Datatable 像下面的结构,

[
   {
        "Product P/N": "12",
        "Brand": "A"
   },
   {
        "Product P/N": "34",
        "Brand": "B"
   }
]

然后,我试着把它做成TableData。但是 Product P/N 全部为空。

var table = this.DataTable.ToList<TableData>();
var a = table.FirstOrDefault().ProductPN;   //  null
var b = table.FirstOrDefault().Brand;       //  A

数据表扩展:

public static List<T> ToList<T>(this DataTable table) where T : new()
{
    IList<PropertyInfo> properties = typeof(T).GetProperties().ToList();
    IList<T> result = new List<T>();

    foreach (var row in table.Rows)
    {
        var item = MappingItem<T>((DataRow)row, properties);
        result.Add(item);
    }

    return result.ToList();
}

Class:

public class TableData
{
    [JsonProperty(PropertyName = "Product P/N")]
    public string ProductPN{ get; set; }
    public string Brand { get; set; }
}

映射项

private static T MappingItem<T>(DataRow row, IList<PropertyInfo> properties) where T : new()
{
    T item = new T();
    foreach (var property in properties)
    {
        var PtName = property.Name;

        if (!string.IsNullOrEmpty(property.ToDescription()) && row.Table.Columns.Contains(property.ToDescription()))
        {
            PtName = property.ToDescription();
        }

        if (row.Table.Columns.Contains(PtName))
        {
            if (property.PropertyType == typeof(string))
            {
                if (row[PtName] != null && row[PtName] != DBNull.Value)
                {
                    property.SetValue(item, row[PtName].ToString(), null);
                }
                else
                {
                    property.SetValue(item, string.Empty, null);
                }
            }
            else if (property.PropertyType == typeof(bool))
            {
                if (row[PtName].ToString().ToUpper() == "TRUE")
                {
                    property.SetValue(item, true, null);
                }
                else
                {
                    property.SetValue(item, false, null);
                }
            }
            else if (property.PropertyType == typeof(DateTime) || property.PropertyType == typeof(DateTime?))
            {
                DateTime dt = new DateTime();
                if (row[PtName] != DBNull.Value && DateTime.TryParse(row[PtName].ToString(), out dt))
                {
                    property.SetValue(item, dt, null);
                }
                else
                {
                    property.SetValue(item, null, null);
                }
            }
            else if (property.PropertyType == typeof(decimal))
            {
                decimal val = new decimal();
                decimal.TryParse(row[PtName].ToString(), out val);
                property.SetValue(item, val, null);
            }
            else if (property.PropertyType == typeof(decimal?))
            {
                if (row[PtName] == DBNull.Value || row[PtName].ToString() == null)
                {
                    property.SetValue(item, null, null);
                }
                else
                {
                    decimal val = new decimal();
                    decimal.TryParse(row[PtName].ToString(), out val);
                    property.SetValue(item, val, null);
                }
            }
            else if (property.PropertyType == typeof(double))
            {
                decimal val = new decimal();
                decimal.TryParse(row[PtName].ToString(), out val);
                property.SetValue(item, Convert.ToDouble(val), null);
            }
            else if (property.PropertyType == typeof(Int16))
            {
                decimal val = new decimal();
                decimal.TryParse(row[PtName].ToString(), out val);
                property.SetValue(item, Convert.ToInt16(val), null);
            }
            else if (property.PropertyType == typeof(Int32))
            {
                decimal val = new decimal();
                decimal.TryParse(row[PtName].ToString(), out val);
                property.SetValue(item, Convert.ToInt32(val), null);
            }
            else if (property.PropertyType == typeof(Int64))
            {
                decimal val = new decimal();
                decimal.TryParse(row[PtName].ToString(), out val);
                property.SetValue(item, Convert.ToInt64(val), null);
            }
            else
            {
                if (row[PtName] != DBNull.Value)
                {
                    property.SetValue(item, row[PtName], null);
                }
            }
        }
    }
    return item;
}

ToDescription():

public static string ToDescription(this PropertyInfo Object)
{
    object[] attrs = Object.GetCustomAttributes(typeof(Display), false);
    if (null != attrs && attrs.Length > 0) return ((Display)attrs[0]).Text;
    return Object.Name.ToString();
}

我怎样才能真正获得带有 space 或特殊字符的名称字段?

对于您的 ProductPN 属性,您应用的 JsonProperty 属性不是 ToDescription() 方法中的 Display 属性。

因此您将获得默认的 属性 名称。

解决方案

为避免中断现有的 ToDescription() 方法,您需要应用此逻辑:

  1. JsonPropertyAttribute 检索属性。
  2. DisplayAttribute 检索属性。
  3. Return默认Property.Name.
using Newtonsoft.Json;

public static string ToDescription(this PropertyInfo property)
{
    try
    {
        object[] descriptionAttrs = property.GetCustomAttributes(typeof(JsonPropertyAttribute), false);
        if (descriptionAttrs != null && descriptionAttrs.Length > 0)
        {
            JsonPropertyAttribute description = (JsonPropertyAttribute)descriptionAttrs[0];         
            return description.PropertyName;
        }

        object[] attrs = property.GetCustomAttributes(typeof(DisplayAttribute), false);
        if (null != attrs && attrs.Length > 0) 
            return ((DisplayAttribute)attrs[0]).Name;
        
        return property.Name.ToString();
    }
    catch
    {
        return null;
    }
}

Sample Demo