关于.Net Remoting中Lambda表达式的串行化问题

最近的一个项目中需要使用.Net Remoting来进行Client端与Server端的通信,其中Server端有一个数据库查询方法使用Lambda表达式作为参数,Client端将需要查询的条件以Lambda表达式的形式传给Server端运行然后返回查询结果,Server端函数如下:

 

ExpandedBlockStart.gif
         public  List < object >  SearchEntities < T > (Expression < Func < T,  bool >>  expression)  where  T :  class new ()
        {
            DataClassesDataContext dc 
=   new  DataClassesDataContext(SQLiteHelper.GetConnection());
            Table
< T >  tables  =  dc.GetTable < T > ();
            
return  tables.Where(expression).ToList();
        }

 

使用时发现Linq的Expression类没有标记Serializable,所以没法串行化传递该参数。于是想找到一个可串行化对象作为中间对象,将Lambda表达式转成这个中间对象传给Server端,Server端再将其还原成Lambda表达式,最后在Server端进行查询,如图:

 

 

 

在网上找到了三种方法可以将Expression转换成可串行化的对象,但是使用过程中发现这些方法都有问题:

 

1. 使用Dynamic Expression类,本来设想使用Expression.ToString()方法将Expression转换成字符串,然后将该字符串传递给Server端,Server端再使用ParseLambda方法将字符串转换成Expression,但是发现DynamicExpression类的ParseLambda方法中的string expression变量接收的是这个类自己定义的一套类似于Lambda语法的表达式,所以Expression.ToString()方法生成的字符串无法使用ParseLambda方法将其转换成Expression对象。

 

 

 

ExpandedBlockStart.gif
public   void  TestDynamicExpression()
{
    //not work!
    Expression
< Func < UserInfo,  bool >>  expression  =  u  =>  u.UserName  ==   " admin " ;
    
string  expressionStr  =  expression.ToString();
    Expression
< Func < UserInfo,  bool >>  result  =  DynamicExpression.ParseLambda < UserInfo,  bool > (expressionStr);
}

 

2. 使用Expression Tree Serialization类,该类可以将Expression串行化成XElement对象,也可以将XElement对象反串行化成Expression。

ExpandedBlockStart.gif
Expression < Func < int int int >>  addExpr  =  (x, y)  =>  x  +  y;
ExpressionSerializer serializer 
=   new  ExpressionSerializer();
XElement addXml 
=  serializer.Serialize(addExpr);
Expression
< Func < int , int , int >>  addExpResult  =  serializer.Deserialize < Func < int , int , int >> (addXml);

 

 

本以为这个类可以很完美的解决.Net Remoting中Expression无法串行化的问题,但是在使用过程中发现还有下面的问题:

 

ExpandedBlockStart.gif
     class  Program
    {
        
static   void  Main( string [] args)
        {
            
// Test1: work!
            Expression < Func < UserInfo,  bool >>  expression  =  u  =>  u.UserName  ==   " admin " ;
            XElement xml 
=  ExpressionSerializer.Serialize(expression);
            Expression
< Func < UserInfo,  bool >>  result  =  ExpressionSerializer.Deserialize < Func < UserInfo,  bool >> (xml);

            
// Test2: not work!
            BLL bll  =   new  BLL( " admin " );
            Expression
< Func < UserInfo,  bool >>  expression1  =  u  =>  u.UserName  ==  bll.value;
            XElement xml1 
=  ExpressionSerializer.Serialize(expression1);
            Expression
< Func < UserInfo,  bool >>  r  =  ExpressionSerializer.Deserialize < Func < UserInfo,  bool >> (xml1);
        }
    }

    
public   class  BLL
    {
        
public   string  value {  get set ; }

        
public  BLL( string  value)
        {
            
this .value  =  value;
        }
    }

 

 

Test1是可以通过的,expression中的lambda表达式翻译成 u => (u.UserName = "admin"),因为"admin"是常量所以直接添加到表达式里。

Test2无法通过测试,expression1中的lambda表达式翻译成 u=> (u.UserName = TestServer.Program+<>c__DisplayClass0.value),因为value是BLL类的成员,所以就翻译成了一个类.成员的形式,但是这个方法在Deserialize的时候,就无法翻译TestServer.Program+<>c__DisplayClass0的类型,而且在Server端也无法知道BLL类的实例中value的值。

 

3. CodeDom, 这种方法的问题和上面的一样,也是当变量包含在一个类型中的时候,无法将真正的值变成Expression中的值。

 

ExpandedBlockStart.gif
public   void  Test()
{
    
// not work!
    BLL bll  = new BLL("admin");
    Expression < Func < UserInfo,  bool >>  expression  =  u  =>  u.UserName  == bll.value ;
    
string  expressionStr  =  expression.ToString();

    Dictionary
< string string >  providerOptions  =   new  Dictionary < string string > ();
    providerOptions.Add(
" CompilerVersion " " v3.5 " );
    CSharpCodeProvider provider 
=   new  CSharpCodeProvider(providerOptions);
    CompilerResults results 
=  provider.CompileAssemblyFromSource
    (
        
new  CompilerParameters( new [] {  " System.Core.dll "  }),
        
@" using System;
        using System.Linq.Expressions;

        class foo
        {
            public static Expression<Func<UserInfo, bool>> GetExpression()
            {
                return 
"   +  expressionStr  +   @" ;
            }
        }
"
    );

    Expression
< Func < UserInfo,  bool >>  result  =  (Expression < Func < UserInfo,  bool >> )results.CompiledAssembly.GetType( " foo " ).GetMethod( " GetExpression " ).Invoke( null null );
}

 

 

 上面三个方法花了一整天的时间试验以后发现都不好使,所以冒昧的发到首页想向大家请教一下,关于Lambda表达式的串行化问题大家是如何解决的?多谢^_^

 

转载于:https://www.cnblogs.com/reinstallsys/archive/2010/08/17/1801099.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值