C# 使用表达式创建动态方法

 1、参考https://www.cnblogs.com/xiaoZhang521/p/11374258.html

             https://stackoverflow.com/questions/14890516/how-to-use-expression-makeindex-in-linq-expressions/14890856#14890856

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]);
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值