随笔- 3  评论- 8  文章- 0 

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

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

 

        public List<object> SearchEntities<T>(Expression<Func<T, bool>> expression) where T : classnew()
        {
            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对象。

 

 

 

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。

Expression<Func<intintint>> 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无法串行化的问题,但是在使用过程中发现还有下面的问题:

 

    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 { getset; }

        
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中的值。

 

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
<stringstring> providerOptions = new Dictionary<stringstring>();
    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(nullnull);
}

 

 

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

 

posted on 2010-08-17 00:20  reinstallsys  阅读(637)  评论(7编辑  收藏