LambdaParser:解析字符串为Lambda表达式并编译为委托

最近刚刚离了职,便休息一会做点自己想做的事,于是花点时间写了这个解析字符串为Lambda表达式并编译为委托的模块:LambdaParser。

介绍

先举个最简单的例子让大家明白LambdaParser模块究竟做什么:

Func<intstring> f = ExpressionParserManager.ParseDelegate<Func<intstring>>(
    
"m=>2+m.ToString(\"000\")");
string result = f(2); // "2002"

简单的说,LambdaParser模块就是在运行时编译Lambda表达式

原理

LambdaParser的最主要方法ParseDelegate接受一个代码字符串,返回一个委托。
LambdaParser会分析输入的代码字符串,然后一个一个构造Lambda Expression,最后编译成委托。
这样,我们就能动态编译并执行代码
若是每次都这样,性能当然好不到哪里去,于是我在ExpressionParserManager做缓存,在下次调用时从缓存里取委托。

特点

在运行时编译Lambda表达式不是一个常规解决方案,但有时候很有用,它比反射更灵活,更快,更易懂。

一些说明

1.基于Lambda表达式,所以当然也不支持Lambda表达式不支持的,如:赋值操作等。

2.只支持Lambda表达式,不支持Lambda语句。也就是说不能写多条Lambda语句,所以if,for,while等肯定是不支持的。

3.理所当然,支持数字运算,支持字符串拼接。目前尚未做编译优化,比如:1+2这种常量运算本来是可以在编译的时候就计算出来,但现在是原原本本的编译出来,在运行时去计算。字符串的拼接也一样。

4.目前尚不支持checked运算。

5.由于我是看了老赵的《这下没理由嫌Eval的性能差了吧?》才有这想法的,对于那一段Expression代码 (DynamicPropertyAccessor构造函数),当时花了N+M次的来回阅读,才勉强弄明白意思,于是计划写这个,所以我用老赵的思路也实 现了一个FastEval,由于我这个类库本来就是做解析的,所以对于FastEval的参数也就原生的支持表达式语句,而不仅仅是属性名,所以我认为我 这个FastEval实现比原本的Eval更快,更灵活:)
example:<%#FastEval("Sex?\"男\":\"女\"")%>

6.本打算同样用老赵的思想实现FastReflectionLib,但发现LambdaParser还有很多事要做,就先搁置。

7.如果本身的Lambda表达式写得有问题,那么报的错误可能会很奇怪,因为时间原因目前没有很友好的错误提示。

结束语

项目中必定会有不少bug,若是解析某个特定code时出意外,希望将输出的code发给我,可以在这里回复,或者发到我邮箱:zhucai+lambdaparser@gmail.com
今天只是简单介绍一下其功能及使用方法,之后有时间我再来详细谈谈设计过程。
我在sourceforge.net申请了个项目:https://sourceforge.net/projects/lambdaparser
但现在还不会玩:(

贴上所有已通过的测试用例,方便弄明白用法:


/// <summary>
/// 数字运算
/// </summary>
[TestMethod]
public void ParseDelegateTest_Number()
{
    {
        Func
<intstring> f = ExpressionParserManager.ParseDelegate<Func<intstring>>(
            
"m=>2+m.ToString(\"000\")");
        
string result = f(2); // "2002"
        Assert.AreEqual(result, "2002");

        
string code = "()=>1+2-3*4/2+20%7";
        
int expected = 1 + 2 - 3 * 4 / 2 + 20 % 7;

        Func
<int> func = ExpressionParserManager.ParseDelegate<Func<int>>(code);

        
int actual = func();

        Assert.AreEqual(expected, actual);
    }
    {
        
string code = "()=>2+3*4/2-4%(2+1)+32-43*(6-4)+3.3";
        
double expected = 2 + 3 * 4 / 2 - 4 % (2 + 1+ 32 - 43 * (6 - 4+ 3.3;

        Func
<double> func = ExpressionParserManager.ParseDelegate<Func<double>>(code);

        
double actual = func();

        Assert.AreEqual(expected, actual);
    }
    {
        
string code = "()=>2+3*4/2-4%(2.4+1)+32-43*(6-4)+3.3*(322/(43-(3-1)))";
        
double expected = 2 + 3 * 4 / 2 - 4 % (2.4 + 1+ 32 - 43 * (6 - 4+ 3.3 * (322 / (43 - (3 - 1)));

        Func
<double> func = ExpressionParserManager.ParseDelegate<Func<double>>(code);

        
double actual = func();

        Assert.AreEqual(expected, actual);
    }
}
/// <summary>
/// 字符串拼接和函数调用
/// </summary>
[TestMethod]
public void ParseDelegateTest_StringAdd()
{
    
string code = "2.ToString()+3+(4*2)";
    
string expected = "238";

    Func
<string> func = ExpressionParserManager.ParseDelegate<Func<string>>(code);

    
string actual = func();

    Assert.AreEqual(expected, actual);
}
/// <summary>
/// 成员访问,方法调用,构造函数(传参)
/// </summary>
[TestMethod]
public void ParseDelegateTest_Member_Method_Ctor()
{
    
string code = "()=>new Test_Zhucai.LambdaParser.TestClass(9,2).Member1";
    
string code2 = "()=>new Test_Zhucai.LambdaParser.TestClass(){Member1 = 5,Member2 = 4}.GetMemberAll()";

    Func
<int> func = ExpressionParserManager.ParseDelegate<Func<int>>(code);
    Func
<int> func2 = ExpressionParserManager.ParseDelegate<Func<int>>(code2);

    
int actual = func();
    
int actual2 = func2();

    Assert.AreEqual(actual, actual2);
}
/// <summary>
/// 委托传多个参数
/// </summary>
[TestMethod]
public void ParseDelegateTest_MultiLambdaParam()
{
    
string code = "(m,n,l)=>m+n+l"// m:1 n:2 l:"3"
    string expected = "33";

    Func
<intintstringstring> func = ExpressionParserManager.ParseDelegate<Func<intintstringstring>>(code);

    
string actual = func(12"3");

    Assert.AreEqual(expected, actual);
}
/// <summary>
/// new数组,数组访问
/// </summary>
[TestMethod]
public void ParseDelegateTest_Array()
{
    
string code = "()=>new string[]{\"aa\",\"bb\"}[1]";
    
string expected = "bb";

    Func
<string> func = ExpressionParserManager.ParseDelegate<Func<string>>(code);

    
string actual = func();

    Assert.AreEqual(expected, actual);
}
/// <summary>
/// new数组,数组访问2
/// </summary>
[TestMethod]
public void ParseDelegateTest_Array2()
{
    
string code = "()=>new string[5].Length";
    
int expected = 5;

    Func
<int> func = ExpressionParserManager.ParseDelegate<Func<int>>(code);

    
int actual = func();

    Assert.AreEqual(expected, actual);
}
/// <summary>
/// new多维数组
/// </summary>
[TestMethod]
public void ParseDelegateTest_ArrayMultiRank()
{
    
string code = "()=>new string[5,4].Rank";
    
int expected = 2;

    Func
<int> func = ExpressionParserManager.ParseDelegate<Func<int>>(code);

    
int actual = func();

    Assert.AreEqual(expected, actual);
}
/// <summary>
/// 索引器访问
/// </summary>
[TestMethod]
public void ParseDelegateTest_Indexer()
{
    
string code = "m=>(string)m[1]";
    
string expected = "bb";

    Func
<ArrayList, string> func = ExpressionParserManager.ParseDelegate<Func<ArrayList, string>>(code);

    
string actual = func(new ArrayList(new string[] { "aa""bb" }));

    Assert.AreEqual(expected, actual);
}
/// <summary>
/// 重复生成
/// </summary>
[TestMethod]
public void ParseDelegateTest_Repeater()
{
    
string code = "m=>(string)m[1]";
    
string expected = "bb";

    Func
<ArrayList, string> func = ExpressionParserManager.ParseDelegate<Func<ArrayList, string>>(code);
    func 
= ExpressionParserManager.ParseDelegate<Func<ArrayList, string>>(code);

    
string actual = func(new ArrayList(new string[] { "aa""bb" }));

    Assert.AreEqual(expected, actual);
}
/// <summary>
/// 成员初始化
/// </summary>
[TestMethod]
public void ParseDelegateTest_MemberInit()
{
    
string code = "()=>new Test_Zhucai.LambdaParser.TestClass(){Member1 = 20}.ToString()";
    
string expected = "20";

    Func
<string> func = ExpressionParserManager.ParseDelegate<Func<string>>(code);

    
string actual = func();

    Assert.AreEqual(expected, actual);
}
/// <summary>
/// 测试操作符typeof,sizeof
/// </summary>
[TestMethod]
public void ParseDelegateTest_OperatorTypeofSizeof()
{
    
string code = "()=>typeof(string).FullName+sizeof(int)";
    
string expected = typeof(string).FullName + sizeof(int);

    Func
<string> func = ExpressionParserManager.ParseDelegate<Func<string>>(code);

    
string actual = func();

    Assert.AreEqual(expected, actual);
}
/// <summary>
/// 测试操作符!
/// </summary>
[TestMethod]
public void ParseDelegateTest_OperatorNot()
{
    
string code = "(m)=>!m";
    
bool expected = true;

    Func
<boolbool> func = ExpressionParserManager.ParseDelegate<Func<boolbool>>(code);

    
bool actual = func(false);

    Assert.AreEqual(expected, actual);
}
/// <summary>
/// 测试操作符~
/// </summary>
[TestMethod]
public void ParseDelegateTest_OperatorBitNot()
{
    
string code = "()=>~9";
    
int expected = ~9;

    Func
<int> func = ExpressionParserManager.ParseDelegate<Func<int>>(code);

    
int actual = func();

    Assert.AreEqual(expected, actual);
}
/// <summary>
/// 测试操作符convert()
/// </summary>
[TestMethod]
public void ParseDelegateTest_OperatorConvert()
{
    
string code = "()=>(int)(9.8+3.3)";
    
int expected = (int)(9.8 + 3.3);

    Func
<int> func = ExpressionParserManager.ParseDelegate<Func<int>>(code);

    
int actual = func();

    Assert.AreEqual(expected, actual);
}
/// <summary>
/// 测试操作符>>,<<
/// </summary>
[TestMethod]
public void ParseDelegateTest_OperatorBitShift()
{
    
string code = "()=>(9>>3)-(5<<2)";
    
int expected = (9 >> 3- (5 << 2);

    Func
<int> func = ExpressionParserManager.ParseDelegate<Func<int>>(code);

    
int actual = func();

    Assert.AreEqual(expected, actual);
}
/// <summary>
/// 测试操作符>
/// </summary>
[TestMethod]
public void ParseDelegateTest_OperatorGreaterThan()
{
    {
        
string code = "()=>9>2";
        
bool expected = (9 > 2);

        Func
<bool> func = ExpressionParserManager.ParseDelegate<Func<bool>>(code);

        
bool actual = func();

        Assert.AreEqual(expected, actual);
    }
    {
        
string code = "()=>2>9";
        
bool expected = (2 > 9);

        Func
<bool> func = ExpressionParserManager.ParseDelegate<Func<bool>>(code);

        
bool actual = func();

        Assert.AreEqual(expected, actual);
    }
    {
        
string code = "()=>2>2";
        
bool expected = (2 > 2);

        Func
<bool> func = ExpressionParserManager.ParseDelegate<Func<bool>>(code);

        
bool actual = func();

        Assert.AreEqual(expected, actual);
    }
}
/// <summary>
/// 测试操作符<
/// </summary>
[TestMethod]
public void ParseDelegateTest_OperatorLessThan()
{
    {
        
string code = "()=>9<2";
        
bool expected = (9 < 2);

        Func
<bool> func = ExpressionParserManager.ParseDelegate<Func<bool>>(code);

        
bool actual = func();

        Assert.AreEqual(expected, actual);
    }
    {
        
string code = "()=>2<9";
        
bool expected = (2 < 9);

        Func
<bool> func = ExpressionParserManager.ParseDelegate<Func<bool>>(code);

        
bool actual = func();

        Assert.AreEqual(expected, actual);
    }
    {
        
string code = "()=>2<2";
        
bool expected = (2 < 2);

        Func
<bool> func = ExpressionParserManager.ParseDelegate<Func<bool>>(code);

        
bool actual = func();

        Assert.AreEqual(expected, actual);
    }
}
/// <summary>
/// 测试操作符<=
/// </summary>
[TestMethod]
public void ParseDelegateTest_OperatorLessThanOrEqual()
{
    {
        
string code = "()=>9<=2";
        
bool expected = (9 <= 2);

        Func
<bool> func = ExpressionParserManager.ParseDelegate<Func<bool>>(code);

        
bool actual = func();

        Assert.AreEqual(expected, actual);
    }
    {
        
string code = "()=>2<=2";
        
bool expected = (2 <= 2);

        Func
<bool> func = ExpressionParserManager.ParseDelegate<Func<bool>>(code);

        
bool actual = func();

        Assert.AreEqual(expected, actual);
    }
    {
        
string code = "()=>2<=9";
        
bool expected = (2 <= 9);

        Func
<bool> func = ExpressionParserManager.ParseDelegate<Func<bool>>(code);

        
bool actual = func();

        Assert.AreEqual(expected, actual);
    }
}
/// <summary>
/// 测试操作符>=
/// </summary>
[TestMethod]
public void ParseDelegateTest_OperatorGreaterThanOrEqual()
{
    {
        
string code = "()=>9>=2";
        
bool expected = (9 >= 2);

        Func
<bool> func = ExpressionParserManager.ParseDelegate<Func<bool>>(code);

        
bool actual = func();

        Assert.AreEqual(expected, actual);
    }
    {
        
string code = "()=>2>=2";
        
bool expected = (2 >= 2);

        Func
<bool> func = ExpressionParserManager.ParseDelegate<Func<bool>>(code);

        
bool actual = func();

        Assert.AreEqual(expected, actual);
    }
    {
        
string code = "()=>2>=9";
        
bool expected = (2 >= 9);

        Func
<bool> func = ExpressionParserManager.ParseDelegate<Func<bool>>(code);

        
bool actual = func();

        Assert.AreEqual(expected, actual);
    }
}
/// <summary>
/// 测试操作符==
/// </summary>
[TestMethod]
public void ParseDelegateTest_OperatorEqual()
{
    {
        
string code = "()=>9==2";
        
bool expected = (9 == 2);

        Func
<bool> func = ExpressionParserManager.ParseDelegate<Func<bool>>(code);

        
bool actual = func();

        Assert.AreEqual(expected, actual);
    }
    {
        
string code = "()=>2==2";
        
bool expected = (2 == 2);

        Func
<bool> func = ExpressionParserManager.ParseDelegate<Func<bool>>(code);

        
bool actual = func();

        Assert.AreEqual(expected, actual);
    }
    {
        
string code = "()=>2==9";
        
bool expected = (2 == 9);

        Func
<bool> func = ExpressionParserManager.ParseDelegate<Func<bool>>(code);

        
bool actual = func();

        Assert.AreEqual(expected, actual);
    }
}
/// <summary>
/// 测试操作符!=
/// </summary>
[TestMethod]
public void ParseDelegateTest_OperatorNotEqual()
{
    {
        
string code = "()=>9!=2";
        
bool expected = (9 != 2);

        Func
<bool> func = ExpressionParserManager.ParseDelegate<Func<bool>>(code);

        
bool actual = func();

        Assert.AreEqual(expected, actual);
    }
    {
        
string code = "()=>2!=2";
        
bool expected = (2 != 2);

        Func
<bool> func = ExpressionParserManager.ParseDelegate<Func<bool>>(code);

        
bool actual = func();

        Assert.AreEqual(expected, actual);
    }
    {
        
string code = "()=>2!=9";
        
bool expected = (2 != 9);

        Func
<bool> func = ExpressionParserManager.ParseDelegate<Func<bool>>(code);

        
bool actual = func();

        Assert.AreEqual(expected, actual);
    }
}
/// <summary>
/// 测试操作符is
/// </summary>
[TestMethod]
public void ParseDelegateTest_OperatorIs()
{
    {
        
string code = "(m)=>((object)m) is int";
        
bool expected = ((object)2is int;

        Func
<objectbool> func = ExpressionParserManager.ParseDelegate<Func<objectbool>>(code);

        
bool actual = func(2);

        Assert.AreEqual(expected, actual);
    }
    {
        
string code = "()=>((object)\"abc\") is int";
        
bool expected = ((object)"abc"is int;

        Func
<bool> func = ExpressionParserManager.ParseDelegate<Func<bool>>(code);

        
bool actual = func();

        Assert.AreEqual(expected, actual);
    }
}
/// <summary>
/// 测试操作符as
/// </summary>
[TestMethod]
public void ParseDelegateTest_OperatorAs()
{
    {
        
string code = "(m)=>((object)m) as string";
        
string expected = ((object)2as string;

        Func
<objectstring> func = ExpressionParserManager.ParseDelegate<Func<objectstring>>(code);

        
string actual = func(2);

        Assert.AreEqual(expected, actual);
    }
    {
        
string code = "()=>((object)\"abc\") as string";
        
string expected = ((object)"abc"as string;

        Func
<string> func = ExpressionParserManager.ParseDelegate<Func<string>>(code);

        
string actual = func();

        Assert.AreEqual(expected, actual);
    }
}
/// <summary>
/// 测试操作符^
/// </summary>
[TestMethod]
public void ParseDelegateTest_OperatorExclusiveOr()
{
    
string code = "()=>3^7";
    
int expected = 3 ^ 7;

    Func
<int> func = ExpressionParserManager.ParseDelegate<Func<int>>(code);

    
int actual = func();

    Assert.AreEqual(expected, actual);
}
/// <summary>
/// 测试操作符&
/// </summary>
[TestMethod]
public void ParseDelegateTest_OperatorAnd()
{
    
string code = "()=>3&7";
    
int expected = 3 & 7;

    Func
<int> func = ExpressionParserManager.ParseDelegate<Func<int>>(code);

    
int actual = func();

    Assert.AreEqual(expected, actual);
}
/// <summary>
/// 测试操作符|
/// </summary>
[TestMethod]
public void ParseDelegateTest_OperatorOr()
{
    
string code = "()=>3|7";
    
int expected = 3 | 7;

    Func
<int> func = ExpressionParserManager.ParseDelegate<Func<int>>(code);

    
int actual = func();

    Assert.AreEqual(expected, actual);
}
/// <summary>
/// 测试操作符&&
/// </summary>
[TestMethod]
public void ParseDelegateTest_OperatorAndAlso()
{
    {
        
string code = "()=>true&&false";
        
bool expected = true && false;

        Func
<bool> func = ExpressionParserManager.ParseDelegate<Func<bool>>(code);

        
bool actual = func();

        Assert.AreEqual(expected, actual);
    }
    {
        
string code = "()=>true&&true";
        
bool expected = true && true;

        Func
<bool> func = ExpressionParserManager.ParseDelegate<Func<bool>>(code);

        
bool actual = func();

        Assert.AreEqual(expected, actual);
    }
    {
        
string code = "()=>false && false";
        
bool expected = false && false;

        Func
<bool> func = ExpressionParserManager.ParseDelegate<Func<bool>>(code);

        
bool actual = func();

        Assert.AreEqual(expected, actual);
    }
}
/// <summary>
/// 测试操作符||
/// </summary>
[TestMethod]
public void ParseDelegateTest_OperatorOrElse()
{
    {
        
string code = "()=>true||false";
        
bool expected = true || false;

        Func
<bool> func = ExpressionParserManager.ParseDelegate<Func<bool>>(code);

        
bool actual = func();

        Assert.AreEqual(expected, actual);
    }
    {
        
string code = "()=>true||true";
        
bool expected = true || true;

        Func
<bool> func = ExpressionParserManager.ParseDelegate<Func<bool>>(code);

        
bool actual = func();

        Assert.AreEqual(expected, actual);
    }
    {
        
string code = "()=>false||false";
        
bool expected = false || false;

        Func
<bool> func = ExpressionParserManager.ParseDelegate<Func<bool>>(code);

        
bool actual = func();

        Assert.AreEqual(expected, actual);
    }
}
/// <summary>
/// 测试操作符?:
/// </summary>
[TestMethod]
public void ParseDelegateTest_OperatorCondition()
{
    {
        
string code = "()=>1==1?1:2";
        
int expected = 1 == 1 ? 1 : 2;

        Func
<int> func = ExpressionParserManager.ParseDelegate<Func<int>>(code);

        
int actual = func();

        Assert.AreEqual(expected, actual);
    }
    {
        
string code = "()=>1==2?1:2";
        
int expected = 1 == 2 ? 1 : 2;

        Func
<int> func = ExpressionParserManager.ParseDelegate<Func<int>>(code);

        
int actual = func();

        Assert.AreEqual(expected, actual);
    }
}
/// <summary>
/// 测试操作符??
/// </summary>
[TestMethod]
public void ParseDelegateTest_OperatorDoubleQuestionMark()
{
    
string code = "(m)=>m??\"bb\"";
    
string expected = "aa";

    Func
<stringstring> func = ExpressionParserManager.ParseDelegate<Func<stringstring>>(code);

    
string actual = func("aa");

    Assert.AreEqual(expected, actual);

    
// use code to test 2
    expected = "bb";

    actual 
= func(null);

    Assert.AreEqual(expected, actual);
}

/// <summary>
/// 测试一个复杂代码
/// </summary>
[TestMethod]
public void ParseDelegateTest_Other()
{
    {
        
string code = @"()=>new Test_Zhucai.LambdaParser.TestClass()
            {
                Member1 = 3
            }.Member1 == 3 ? new Test_Zhucai.LambdaParser.TestClass[]
        {
            new Test_Zhucai.LambdaParser.TestClass()
            {
                Member1 = 3
            }
        }[4-4].Member1 + 3 * new Test_Zhucai.LambdaParser.TestClass()
            {
                Member2 = 5
            }.Member2 : new Test_Zhucai.LambdaParser.TestClass()
            {
                Member2 = 5,
                Member1 = 9,
            }.GetMemberAll();
";
        
int expected = new Test_Zhucai.LambdaParser.TestClass()
            {
                Member1 
= 3
            }.Member1 
== 3 ? new Test_Zhucai.LambdaParser.TestClass[]
        {
            
new Test_Zhucai.LambdaParser.TestClass()
            {
                Member1 
= 3
            }
        }[
4 - 4].Member1 + 3 * new Test_Zhucai.LambdaParser.TestClass()
            {
                Member2 
= 5
            }.Member2 : 
new Test_Zhucai.LambdaParser.TestClass()
            {
                Member2 
= 5,
                Member1 
= 9,
            }.GetMemberAll();

        Func
<int> func = ExpressionParserManager.ParseDelegate<Func<int>>(code);

        
int actual = func();

        Assert.AreEqual(expected, actual);
    }
    {
        
string code = @"()=>new Test_Zhucai.LambdaParser.TestClass()
            {
                Member1 = 3
            }.Member1 != 3 ? new Test_Zhucai.LambdaParser.TestClass[]
        {
            new Test_Zhucai.LambdaParser.TestClass()
            {
                Member1 = 3
            }
        }[new Test_Zhucai.LambdaParser.TestClass().Member1].Member1 + 3 * new Test_Zhucai.LambdaParser.TestClass()
            {
                Member2 = 5
            }.Member2 : new Test_Zhucai.LambdaParser.TestClass()
            {
                Member2 = 5,
                Member1 = 9,
            }.GetMemberAll();
";
        
int expected = new Test_Zhucai.LambdaParser.TestClass()
        {
            Member1 
= 3
        }.Member1 
!= 3 ? new Test_Zhucai.LambdaParser.TestClass[]
        {
            
new Test_Zhucai.LambdaParser.TestClass()
            {
                Member1 
= 3
            }
        }[
new Test_Zhucai.LambdaParser.TestClass().Member1].Member1 + 3 * new Test_Zhucai.LambdaParser.TestClass()
        {
            Member2 
= 5
        }.Member2 : 
new Test_Zhucai.LambdaParser.TestClass()
        {
            Member2 
= 5,
            Member1 
= 9,
        }.GetMemberAll();

        Func
<int> func = ExpressionParserManager.ParseDelegate<Func<int>>(code);

        
int actual = func();

        Assert.AreEqual(expected, actual);
    }
}
public class TestClass
{
    
public int Member1 { getset; }
    
public int Member2;
    
public TestClass()
    {
    }
    
public TestClass(int member, int member2)
    {
        
this.Member1 = member;
        
this.Member2 = member2;
    }
    
public int GetMemberAll()
    {
        
return this.Member1 + this.Member2;
    }
    
public override string ToString()
    {
        
return Member1.ToString();
    }
}

 

共有0个回答