Effective C# 学习笔记(四十二)理解Expression API的使用方式
2011-08-03 22:49 小郝(Kaibo Hao) 阅读(679) 评论(1) 编辑 收藏 举报.NET原来就拥有反射的机制来处理运行时的代码动态构建与使用。但这种代码的构建比较复杂,难以维护。而C#的LINQ和Dynamic支持使这个特性更加简单和容易使用。那就是使用Expression 表达式来为运行时提供动态业务逻辑。
- 在传输框架(WCF,Remoting,WebServices)中使用Expression表达式,来应对服务端逻辑更改。
在客户端调用WCF,Remoting,WebServices服务时,往往需要用代码生成工具生成许多代理代码,而当服务端服务的方法改变,比如新增新的方法或参数改变后,客户端的代码就面临着许多重新生成代理的工作。Expression的动态特性可以简化这些工作。
其原理首先是创建一个以表达式作为参数的方法,并对表达式中的参数进行Lamda表达式的转换,以保证各种传入方式(静态值、索引器、属性访问)的实现。
如下代码所示:
var client = new ClientProxy<IService>();
var result = client.CallInterface<string>(srver => srver.DoWork(172));
public TResult CallInterface<TResult>(Expression<Func<T, TResult>> op)
{
var exp = op.Body as MethodCallExpression;
var methodName = exp.Method.Name;
var methodInfo = exp.Method;
var allParameters = from element in exp.Arguments
select processArgument(element);//处理所有的方法参数
Console.WriteLine("Calling {0}", methodName);
foreach (var parm in allParameters)
Console.WriteLine("\tParameter type = {0}, Value = {1}", parm.Item1, parm.Item2);
return default(TResult);
}
//这个方法将参数处理为lamda表达式,以便应对方法返回值,属性调用,索引器等返回的表达式值
private Tuple<Type, object> processArgument(Expression element)
{
object argument = default(object);
LambdaExpression l = Expression.Lambda(Expression.Convert(element, element.Type));
Type parmType = l.ReturnType;
argument = l.Compile().DynamicInvoke();
return Tuple.Create(parmType, argument);//这里的lamda表达式在示例中创建为()=>172
}
- 整合多系统类似类型
假如你需要整合多个公司维护的系统的联系人对象到你的系统中,而这些系统中对于contact(联系人)类型定义了不同的名称,且拥有不同的字段,这时你需要的做的就是求同存异。下面的代码通过构建一个通用转换器,使被转换类型中与目标类型的public、实例、同名属性进行同名赋值。
class CustomConverter<TSource, TDest>
{
private Func<TSource,TDest> converter;
private void CreateConverterIfNeeded()
{
if (converter == null)
{
//创建原类型的对象作为参数
var source = Expression.Parameter(typeof(TSource),"source");
//创建目标类型的对象作为临时变量
var dest = Expression.Variable(typeof(TDest),"dest");
//首先,获取原类型的公有实例属性
var assignments = from srcProp in
typeof(TSource).GetProperties(
BindingFlags.Public |
BindingFlags.Instance)
where srcProp.CanRead
//获取与原类型的属性名称相同的公有实例属性
let destProp = typeof(TDest).
GetProperty(
srcProp.Name,
BindingFlags.Public |
BindingFlags.Instance)
where (destProp != null) &&(destProp.CanWrite)
//构建对应属性赋值的投影
select Expression.Assign(
Expression.Property(dest, destProp),
Expression.Property(source,srcProp));
// put together the body:
var body = new List<Expression>();
body.Add(Expression.Assign(dest,Expression.New(typeof(TDest))));
body.AddRange(assignments);
body.Add(dest);
var expr = Expression.Lambda<Func<TSource, TDest>>(
Expression.Block(
new[] { dest }, // expression parameters
body.ToArray() // body
),
source // lambda expression
);
var func = expr.Compile();
converter = func;
}
}
}
//测试自己构建的类型转换器
CustomConverter<Person1, Person2> customConverter = new CustomConverter<Person1, Person2>();
Person1 person1 = new Person1() { Username = "haokaibo", Address = "BJ", Age = 18 };
Person2 person2 = customConverter.Converter(person1);
Console.WriteLine(person1);
Console.WriteLine(person2);
出处:http://www.cnblogs.com/haokaibo/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。