zoukankan      html  css  js  c++  java
  • Effective C# 学习笔记(四十二)理解Expression API的使用方式

                .NET原来就拥有反射的机制来处理运行时的代码动态构建与使用。但这种代码的构建比较复杂,难以维护。而C#LINQDynamic支持使这个特性更加简单和容易使用。那就是使用Expression 表达式来为运行时提供动态业务逻辑。


    1. 在传输框架(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

    }

     

    1. 整合多系统类似类型

    假如你需要整合多个公司维护的系统的联系人对象到你的系统中,而这些系统中对于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);

  • 相关阅读:
    水晶报表的部署
    成熟是一种明亮而不刺眼的光辉...
    获取页面地址的各种返回值
    索引的基本原理(转)
    cron
    VS2010 测试 普通单元测试
    SQL 学习笔记
    负载均衡
    Expression 常用方法
    轻松实现QQ用户接入
  • 原文地址:https://www.cnblogs.com/haokaibo/p/2126746.html
Copyright © 2011-2022 走看看