1、参考https://www.cnblogs.com/xiaoZhang521/p/11374258.html
2、主要类
/// <summary>
/// 映射实体类
/// </summary>
public static class MapEntityFactory
{
/// <summary>
/// 动态方法结构,类似c语言中的类型定义,以免handleDict中的类型太长
/// </summary>
/// <param name="t"></param>
/// <param name="colSplitChar"></param>
/// <param name="mapValue"></param>
/// <param name="ignoreColumns"></param>
/// <param name="mapColumns"></param>
/// <returns></returns>
public delegate string MapFun(object t, string colSplitChar, Dictionary<string, string> mapValue = null, List<string> ignoreColumns = null, List<string> mapColumns = null);
/// <summary>
/// 缓存转换方法
/// </summary>
public static Dictionary<string, MapFun> handleDict = new Dictionary<string, MapFun>();
/// <summary>
/// 转换
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
/// <param name="colSplitChar">分隔符,如";"</param>
/// <param name="mapValue">映射值</param>
/// <param name="ignoreColumns">忽略的列</param>
/// <param name="mapColumns">映射的列</param>
/// <returns></returns>
public static string ToProtocolString<T>(this T t, string colSplitChar, Dictionary<string, string> mapValue = null, List<string> ignoreColumns = null, List<string> mapColumns = null)
{
MapFun handler = null;
string key = typeof(T).Name;
if (handleDict.ContainsKey(key))
{
handler = (MapFun)handleDict[key];
}
else
{
handler = CreateBuilder<T>();
handleDict.Add(key, handler);
}
return handler(t, colSplitChar, mapValue, ignoreColumns, mapColumns);
}
/// <summary>
/// 创建动态转换方法
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
private static MapFun CreateBuilder<T>()
{
// 属性数据
PropertyInfo[] properties = typeof(T).GetProperties();
// 构建属性列表
properties = BuildProperty(properties);
// define the parameter
var objExpr = Expression.Parameter(typeof(object), "entity");
// code: return (object)dynamicEntity;
var entityExpr = Expression.Convert(objExpr, typeof(T));
var splitChar = Expression.Parameter(typeof(string), "colSplitChar");
var mapValueExpr = Expression.Parameter(typeof(Dictionary<string, string>), "mapValue");
var ignoreColumnsExpr = Expression.Parameter(typeof(List<string>), "ignoreColumns");
var mapColumnsExpr = Expression.Parameter(typeof(List<string>), "mapColumns");
// collect the body
var bodyExprs = new List<Expression>();
var mapLeftExprs = new List<Expression>();
var mapRightExprs = new List<Expression>();
// code: var sbData = new DynamicType();
var sbType = typeof(StringBuilder);
var sbDataExpr = Expression.Variable(sbType, "sbData");
var sbDataTypeExpr = Expression.New(sbType);
var assignDataExpr = Expression.Assign(sbDataExpr, sbDataTypeExpr);
bodyExprs.Add(assignDataExpr);
//Expression ExpColSplitChar = Expression.Constant(splitChar);
MethodInfo appendStringMethod = sbType.GetMethod("Append", new Type[] { typeof(string) });
MethodInfo containsMethod = typeof(List<string>).GetMethod("Contains", new Type[] { typeof(string) });
MethodInfo containKeyMethod = typeof(Dictionary<string, string>).GetMethod("ContainsKey", new Type[] { typeof(string) });
//https://www.cnblogs.com/xiaoZhang521/p/11374258.html
//泛型方法
var appendValueMethod = typeof(MapEntityFactory).GetMethod("AppendValue");
var appendValueMethodT = appendValueMethod.MakeGenericMethod(typeof(T));
var appendDictValue = typeof(MapEntityFactory).GetMethod("AppendDictValue");
var getPropertyInfo = typeof(MapEntityFactory).GetMethod("GetPropertyInfo");
var toString = sbType.GetMethod("ToString", new Type[] { });
var jExpr = Expression.Variable(typeof(int), "j");
var countExpr = Expression.Variable(typeof(int), "count");
var itemExpr= Expression.Variable(typeof(PropertyInfo), "item");
var itemNameExpr = Expression.Variable(typeof(string), "itemName");
var columnNameExpr = Expression.Variable(typeof(string), "columnName");
var propExpr = Expression.Constant(properties);
var proptotalExpr = Expression.Constant(properties.Count());
var namePropertyExpr = Expression.Property(itemExpr, "Name");
var listItemProperty = typeof(List<string>).GetProperty("Item");
var dictItemProperty = typeof(Dictionary<string, string>).GetProperty("Item");
// Creating a label to jump to from a loop.
LabelTarget label = Expression.Label(typeof(void));
LabelTarget continue_label = Expression.Label(typeof(void));
// 添加忽略的属性
bodyExprs.Add(Expression.IfThen(
Expression.Equal(ignoreColumnsExpr, Expression.Constant(null)),
Expression.Assign(ignoreColumnsExpr, Expression.New(typeof(List<string>)))
)
);
foreach(var p in properties)
{
var attr = p.GetCustomAttribute(typeof(MapIgnoreAttribute));
if (attr != null)
{
bodyExprs.Add(Expression.Call(ignoreColumnsExpr, typeof(List<string>).GetMethod("Add"), Expression.Constant(p.Name)));
}
}
// count = properties.Count();
mapLeftExprs.Add(Expression.Assign(countExpr, proptotalExpr));
// j = 0;
mapLeftExprs.Add(Expression.Assign(jExpr, Expression.Constant(0)));
LoopExpression loopLeftExp = Expression.Loop(
Expression.IfThenElse(
Expression.LessThan(jExpr, countExpr),
Expression.Block(
// item = properties[i];
Expression.Assign(itemExpr, Expression.ArrayIndex(propExpr, jExpr)),
Expression.IfThen(Expression.OrElse(Expression.Equal(ignoreColumnsExpr, Expression.Constant(null)),
Expression.Not(Expression.Call(ignoreColumnsExpr, containsMethod, namePropertyExpr))),
Expression.Block(
//Expression.Call(typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }), namePropertyExpr),
//Expression.Call(typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) }), jExpr),
// 显示属性名称
//Expression.Call(typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }), Expression.Property(itemExpr, "Name")),
// 报错:从作用域“”引用了“System.Reflection.PropertyInfo”类型的变量“item”,但该变量未定义”
//Expression.Call(typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }),
// Expression.Constant(
// Expression.Lambda<Func<PropertyInfo>>(itemExpr).Compile()().Name)
// ),
Expression.IfThenElse(Expression.OrElse(Expression.Equal(mapValueExpr, Expression.Constant(null)),
Expression.Not(Expression.Call(mapValueExpr, containKeyMethod, namePropertyExpr))),
Expression.Block(
// sbData.Append(mineInfo.MineCode + ColSplitChar);
// appendMethod = sbType.GetMethod("Append", new Type[] { item.PropertyType });
//valueExpr = Expression.Property(entityExpr, columnName);
//bodyExprs.Add(Expression.Call(sbDataExpr, appendMethod, valueExpr));
// 无法转为下面的数据
//Expression.Call(sbDataExpr,
//sbType.GetMethod("Append", new Type[] { Expression.Property(itemExpr, "PropertyType") }),
//Expression.Property(entityExpr, Expression.Property(itemExpr, "Name")) ),
Expression.Call(appendValueMethodT, sbDataExpr, entityExpr, itemExpr)
),
Expression.Block(
Expression.Call(appendDictValue, sbDataExpr, mapValueExpr, itemExpr)
)
),
//if (i < count - 1)
// bodyExprs.Add(Expression.Call(sbDataExpr, appendStringMethod, splitChar));
Expression.IfThen(Expression.LessThan(jExpr, Expression.Subtract(countExpr, Expression.Constant(1))),
Expression.Call(sbDataExpr, appendStringMethod, splitChar)
)
)
),
Expression.AddAssign(jExpr, Expression.Constant(1)),
Expression.Continue(continue_label, typeof(void))
),
Expression.Break(label)
),
label,
continue_label
);
mapLeftExprs.Add(loopLeftExp);
// count = properties.Count();
mapRightExprs.Add(Expression.Assign(countExpr, Expression.Property(mapColumnsExpr, "Count")));
// i = 0;
mapRightExprs.Add(Expression.Assign(jExpr, Expression.Constant(0)));
LoopExpression loopRightExp = Expression.Loop(
Expression.IfThenElse(
Expression.LessThan(jExpr, countExpr),
Expression.Block(
// columnName = mapColumns[i];
Expression.Assign(columnNameExpr, Expression.MakeIndex(mapColumnsExpr, listItemProperty, new List<Expression> { jExpr })),
Expression.Assign(itemExpr, Expression.Call(getPropertyInfo, new Expression[] { propExpr, columnNameExpr })),
Expression.IfThenElse(Expression.Not(Expression.Equal(itemExpr, Expression.Constant(null))),
Expression.Block(
Expression.IfThenElse(Expression.OrElse(Expression.Equal(mapValueExpr, Expression.Constant(null)),
Expression.Not(Expression.Call(mapValueExpr, containKeyMethod, columnNameExpr))),
Expression.Block(
Expression.Call(appendValueMethodT, sbDataExpr, entityExpr, itemExpr)
),
Expression.Block(
Expression.Call(appendDictValue, sbDataExpr, mapValueExpr, itemExpr)
)
)
),
Expression.Block(
Expression.IfThenElse(Expression.AndAlso(Expression.NotEqual(mapValueExpr, Expression.Constant(null)),
Expression.Not(Expression.Call(mapValueExpr, containKeyMethod, columnNameExpr))),
Expression.Block(
Expression.Call(sbDataExpr, appendStringMethod, Expression.Constant(""))
),
Expression.Block(
Expression.Call(sbDataExpr, appendStringMethod, Expression.MakeIndex(mapValueExpr, dictItemProperty, new List<Expression> { columnNameExpr }))
)
)
)
),
//if (i < count - 1)
// bodyExprs.Add(Expression.Call(sbDataExpr, appendStringMethod, splitChar));
Expression.IfThen(Expression.LessThan(jExpr, Expression.Subtract(countExpr, Expression.Constant(1))),
Expression.Call(sbDataExpr, appendStringMethod, splitChar)
),
Expression.AddAssign(jExpr, Expression.Constant(1)),
Expression.Continue(continue_label, typeof(void))
),
Expression.Break(label)
),
label,
continue_label
);
mapRightExprs.Add(loopRightExp);
mapRightExprs.Add(Expression.Call(typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }), Expression.Call(sbDataExpr, toString)));
var mapLeftBlock = Expression.Block(
mapLeftExprs /* body expressions */);
var mapRightBlock = Expression.Block(
mapRightExprs /* body expressions */);
//if (mapColumns == null || mapColumns.Count < 1)
Expression conditionExpr = Expression.IfThenElse(
Expression.OrElse(Expression.Equal(mapColumnsExpr, Expression.Constant(null)),
Expression.LessThan(Expression.Property(mapColumnsExpr, "Count"), Expression.Constant(1))),
mapLeftBlock,
mapRightBlock
);
bodyExprs.Add(conditionExpr);
bodyExprs.Add(Expression.Call(sbDataExpr, toString));
// code: { ... }
var methodBodyExpr = Expression.Block(
typeof(string), /* return type */
new ParameterExpression[] { sbDataExpr, jExpr, countExpr, itemExpr, columnNameExpr }, /* local variables */
bodyExprs /* body expressions */);
// code: () => { ... }
var lambdaExpr = Expression.Lambda<MapFun>(methodBodyExpr, objExpr, splitChar, mapValueExpr, ignoreColumnsExpr, mapColumnsExpr);
return lambdaExpr.Compile();
}
/// <summary>
/// 从实体中获取数据
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="sb"></param>
/// <param name="entity"></param>
/// <param name="p"></param>
public static void AppendValue<T>(StringBuilder sb, T entity, PropertyInfo p)
{
sb.Append(entity.GetPropertyValue(p));
}
/// <summary>
/// 加入字典中的数据
/// </summary>
/// <param name="sb"></param>
/// <param name="dict"></param>
/// <param name="p"></param>
public static void AppendDictValue(StringBuilder sb, Dictionary<string, string> dict, PropertyInfo p)
{
sb.Append(dict[p.Name]);
}
/// <summary>
/// 获取属性
/// </summary>
/// <param name="properties"></param>
/// <param name="columnName"></param>
public static PropertyInfo GetPropertyInfo(PropertyInfo[] properties, string columnName)
{
return properties.Where(x => x.Name == columnName).SingleOrDefault();
}
/// <summary>
/// 构建Proeryty列表
/// </summary>
/// <param name="pInfos"></param>
/// <returns></returns>
public static PropertyInfo[] BuildProperty(PropertyInfo[] pInfos)
{
Dictionary<int, PropertyInfo> pOrderList = new Dictionary<int, PropertyInfo>();
Dictionary<int, List<PropertyInfo>> pList = new Dictionary<int, List<PropertyInfo>>();
int i = 0;
Type oldType = null;
foreach (var p in pInfos)
{
if (p.MemberType != MemberTypes.Property)
continue;
// 忽略的字段
var attr = p.GetCustomAttribute(typeof(MapIgnoreAttribute));
if (attr != null)
{
continue;
}
// 有排序要求的字段
// 1、父类字段在前,子类字段在后
// 2、根据序号插入到先前的序号中
attr = p.GetCustomAttribute(typeof(MapOrderAttribute), true);
if (attr != null)
{
MapOrderAttribute mapOrder = (MapOrderAttribute)attr;
pOrderList.Add(mapOrder.OrderNumber, p);
}
else
{
if (oldType != p.DeclaringType)
{
i++;
oldType = p.DeclaringType;
pList.Add(i, new List<PropertyInfo>());
pList[i].Add(p);
}
else
{
pList[i].Add(p);
}
}
}
var keyValues = pList.OrderByDescending(x => x.Key);
List<PropertyInfo> pResultList = new List<PropertyInfo>();
foreach (var item in keyValues)
{
pResultList.AddRange(item.Value);
}
foreach(int key in pOrderList.Keys)
{
if (key < pResultList.Count)
pResultList.Insert(key, pOrderList[key]);
else
pResultList.Add(pOrderList[key]);
}
return pResultList.ToArray();
}
}
3、获取属性的值
public static class TypeInfoExtension
{
/// <summary>
/// 获取类的属性名称
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <typeparam name="TProperty"></typeparam>
/// <param name="source"></param>
/// <param name="propery"></param>
/// <returns></returns>
public static string GetPropName<TSource, TProperty>(this TSource source,
Expression<Func<TSource, TProperty>> propery) where TSource : class
{
var body = propery.Body.ToString();
return body.Substring(body.LastIndexOf(".") + 1);
}
public static PropertyInfo GetPropertyInfo<TSource, TProperty>(
Expression<Func<TSource, TProperty>> propertyLambda)
{
Type type = typeof(TSource);
MemberExpression member = propertyLambda.Body as MemberExpression;
if (member == null)
throw new ArgumentException(string.Format(
"Expression '{0}' refers to a method, not a property.",
propertyLambda.ToString()));
PropertyInfo propInfo = member.Member as PropertyInfo;
if (propInfo == null)
throw new ArgumentException(string.Format(
"Expression '{0}' refers to a field, not a property.",
propertyLambda.ToString()));
if (type != propInfo.ReflectedType &&
!type.IsSubclassOf(propInfo.ReflectedType))
throw new ArgumentException(string.Format(
"Expresion '{0}' refers to a property that is not from type {1}.",
propertyLambda.ToString(),
type));
return propInfo;
}
/// <summary>
/// 获取类的属性信息
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <typeparam name="TProperty"></typeparam>
/// <param name="source"></param>
/// <param name="propertyLambda"></param>
/// <returns></returns>
public static PropertyInfo GetPropertyInfo<TSource, TProperty>(this TSource source,
Expression<Func<TSource, TProperty>> propertyLambda) where TSource : class
{
return GetPropertyInfo(propertyLambda);
}
/// <summary>
/// 获取类的属性名称
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <typeparam name="TProperty"></typeparam>
/// <param name="source"></param>
/// <param name="propertyLambda"></param>
/// <returns></returns>
public static string NameOfProperty<TSource, TProperty>(this TSource source,
Expression<Func<TSource, TProperty>> propertyLambda) where TSource : class
{
PropertyInfo prodInfo = GetPropertyInfo(propertyLambda);
return prodInfo.Name;
}
/// <summary>
/// 根据属性名获取属性值
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
/// <param name="t">对象</param>
/// <param name="name">属性名</param>
/// <returns>属性的值</returns>
public static object GetPropertyValue<T>(this T t, string name)
{
Type type = t.GetType();
PropertyInfo p = type.GetProperty(name);
if (p == null)
{
throw new Exception(String.Format("该类型没有名为{0}的属性", name));
}
var param_obj = Expression.Parameter(typeof(T));
var param_val = Expression.Parameter(typeof(object));
// 原有的,非string类型会报转换object错误
转成真实类型,防止Dynamic类型转换成object
//var body_obj = Expression.Convert(param_obj, type);
//var body = Expression.Property(body_obj, p);
//var getValue = Expression.Lambda<Func<T, object>>(body, param_obj).Compile();
//转成真实类型,防止Dynamic类型转换成object
Expression<Func<T, object>> result = Expression.Lambda<Func<T, object>>(Expression.Convert(Expression.Property(param_obj, p), typeof(object)), param_obj);
var getValue = result.Compile();
return getValue(t);
}
/// <summary>
/// 根据属性名获取属性值
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
/// <param name="t">对象</param>
/// <param name="name">属性名</param>
/// <returns>属性的值</returns>
public static object GetPropertyValue<T>(this T t, PropertyInfo p)
{
var param_obj = Expression.Parameter(typeof(T));
var param_val = Expression.Parameter(typeof(object));
//转成真实类型,防止Dynamic类型转换成object
Expression<Func<T, object>> result = Expression.Lambda<Func<T, object>>(Expression.Convert(Expression.Property(param_obj, p), typeof(object)), param_obj);
var getValue = result.Compile();
return getValue(t);
}
}
4、MapIgnoreAttribute
/// <summary>
/// 映射忽略属性
/// </summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class MapIgnoreAttribute : Attribute
{
public MapIgnoreAttribute()
{
}
}
/// <summary>
/// 映射序号
/// </summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class MapOrderAttribute : Attribute
{
public int OrderNumber { get; set; }
public MapOrderAttribute(int orderNumber)
{
this.OrderNumber = orderNumber;
}
}
5、测试
public static void TestMapEntityFactory()
{
var mine = new
{
MineCode = "1234",
ClassTotal = DateTime.Now,
CoalSeam = 10,
};
var mine1 = new
{
MineCode = "4567890",
ClassTotal = DateTime.Now,
CoalSeam = 10,
};
var mapValue = new Dictionary<string, string>()
{
{mine.GetPropName(x => x.ClassTotal), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") },
{ "extraValue", "附加数据" }
};
var data = mine.ToProtocolString(";", mapValue, null, new List<string> { "MineCode", "ClassTotal", "extraValue" });
var mapValue1 = new Dictionary<string, string>()
{
{mine.GetPropName(x => x.ClassTotal), DateTime.Now.AddDays(1).ToString("yyyy-MM-dd HH:mm:ss") }
};
var data1 = mine1.ToProtocolString("~", mapValue1);
Console.WriteLine(data);
Console.WriteLine(data1);
}
4、输出结果
5、表达式清除数据
public void Clear<T>(string methodName)
{
// 使用反射获取方法信息
MethodInfo method = typeof(RadPointEntity).GetMethod(methodName, new Type[] { typeof(T) });
object[] parameters = new object[] { default(T) };
foreach (var key in this.dictRadPoints.Keys)
{
// 调用方法
method.Invoke(this.dictRadPoints[key], parameters);
}
// 使用表达式
var argExp = Expression.Constant(null);
var entityExpr = Expression.Convert(argExp, typeof(T));
var objExpr = Expression.Parameter(typeof(RadPointEntity), "x");
var exp = Expression.Call(objExpr, method, entityExpr);
var lambdaExpr = Expression.Lambda<Action<RadPointEntity>>(exp, objExpr);
Action<RadPointEntity> func = (Action<RadPointEntity>)lambdaExpr.Compile();
foreach (var key in this.dictRadPoints.Keys)
{
func(this.dictRadPoints[key]);
}
}