共享一个从字符串转 Lambda 表达式的类(5)

前几篇文章,我把前提都铺垫好了,下面就说说具体的代码。

 

我为这个转换类取名为 ExpressionParserCore :

  • 需要 SymbolParseResult 类的实例对象和 TypeParser 类的实例对象,分别用于字符串解析和类型解析
  • 需要待分析表达式树的传入参数和传出参数

TypeParser 还需要分析用的命名空间数组、额外的 Assembly 列表。其中 Assembly 列表可以使用 Assembly.LoadFrom("D:\abc.dll") 的方式加载,这对于后续的插件扩展很有帮助。下面这段代码是类的构造函数:

/// <summary>
/// Initializes a new instance of the <see cref="ExpressionParserCore"/> class.
/// </summary>
/// <param name="spResult">The sp result.</param>
/// <param name="delegateType">Type of the delegate.</param>
/// <param name="namespaces">The namespaces.</param>
public ExpressionParserCore(SymbolParseResult spResult, Type delegateType, IEnumerable<string> namespaces = null, IEnumerable<Assembly> assemblies = null)
{
    this.spResult = spResult;
 
    this.typeParser = new TypeParser(ref this.spResult);
    typeParser.SetNamespaces(namespaces);
    typeParser.SetAssemblies(assemblies);
 
    var method = delegateType.GetMethod("Invoke");
    parameterTypes = method.GetParameters().Select(p => p.ParameterType).ToArray();
    returnType = method.ReturnType;
}

但是这样还不够。一般 Lambda 表达式都是有参数的,而且在表达式中也有用到,所以解析的过程中对于 Lambda 参数的解析也必须包含进来:

/// <summary>
/// 处理表达式前缀.
/// </summary>
private void ProcessLambdaPrefix()
{
    // 检查是否有 Lambda 前置符(如: m => )
    if (spResult.Any(p => p.ID == TokenId.LambdaPrefix))
    {
        Token token = spResult.Next();
        if (token.ID == TokenId.OpenParen)
        {
            var bracketContent = spResult.SkipUntil(p => p.ID == TokenId.CloseParen);
            bracketContent.RemoveAt(bracketContent.Count - 1);
 
            if (bracketContent.Any(p => p.ID == TokenId.OpenParen))
                throw new ParserSyntaxErrorException();
 
            // 如果读取到 => 符号表示有
            if (!spResult.NextIs(TokenId.LambdaPrefix))
            {
                spResult.ReturnToIndex(-1);
                return;
            }
 
            // 解析参数
            ResolveParameters(bracketContent).Foreach((p, i) =>
            {
                if (p.ExistType)
                    expParams.Add(Expression.Parameter(typeParser.GetType(p.Type), p.Variable));
                else
                    expParams.Add(Expression.Parameter(parameterTypes[i], p.Variable));
            });
        }
        else if (token.ID == TokenId.Identifier &&
                    (char.IsLetter(token.Text[0]) || token.Text[0] == '_') &&
                    !(token.Text == "true" ||
                    token.Text == "false" ||
                    token.Text == "null" ||
                    token.Text == "sizeof" ||
                    token.Text == "new" ||
                    token.Text == "typeof"))
        {
            if (!spResult.NextIs(TokenId.LambdaPrefix))
            {
                spResult.ReturnToIndex(-1);
                return;
            }
 
            expParams.Add(Expression.Parameter(parameterTypes[0], token.Text));
        }
 
        // 参数表达式个数和传入委托参数个数不匹配判断
        if (expParams.Count != parameterTypes.Length)
            throw new ApplicationException("The count of parameters is not equal.");
    }
}
 
/// <summary>
/// 解析参数并返回配对(类型/变量)的字符单元列表.
/// </summary>
/// <param name="obj">待解析的字符单元列表.</param>
/// <returns>解析完成的字符单元列表.</returns>
private TypeVariable[] ResolveParameters(IEnumerable<Token> obj)
{
    Token selector = new Token { ID = TokenId.Comma, Text = "," };
    var result = new List<TypeVariable>();
    if (ReferenceEquals(obj, null) || !obj.Any())
        return result.ToArray();
 
    if (obj.Last() != selector)
    {
        var list = obj.ToList();
        list.Add(selector);
        obj = list;
    }
    var data = obj.ToArray();
 
    int firstIndex = 0, secondIndex = 0;
    while ((secondIndex = Array.IndexOf(data, selector, firstIndex)) != -1)
    {
        if (secondIndex == firstIndex + 1)
            result.Add(new TypeVariable(null, data[firstIndex]));
        else if (secondIndex == firstIndex + 2)
            result.Add(new TypeVariable(data[firstIndex], data[firstIndex + 1]));
        else
            throw new ParserSyntaxErrorException();
 
        firstIndex = secondIndex + 1;
    }
 
    return result.ToArray();
}

这个方法,可以把它放在构造函数中,也可以放在 ToLambdaExpression 方法里面。忘记了,这涉及到一个类,用于记录类型和变量的键值对:

 

/// <summary>
/// 【类型:变量】键值对
/// </summary>
[DebuggerStepThrough]
[DebuggerDisplay("{Type.Text}, {Variable.Text}")]
public class TypeVariable
{
    /// <summary>
    /// 获取类型字符单元.
    /// </summary>
    public Token Type { get; private set; }
    /// <summary>
    /// 获取变量字符单元.
    /// </summary>
    public Token Variable { get; private set; }
    /// <summary>
    /// 获取一个值, 通过该值指示是否包含类型定义. <c>true</c> 表示包含类型定义.
    /// </summary>
    public bool ExistType { get; private set; }
 
    /// <summary>
    /// 初始化新建一个 <see cref="TypeVariable"/> 类的实例对象.
    /// </summary>
    /// <param name="type">类型字符单元.</param>
    /// <param name="variable">变量字符单元.</param>
    public TypeVariable(Token? type, Token variable)
    {
        Variable = variable;
        if (ExistType = type.HasValue)
            Type = type.Value;
    }
}

 

在这之后,就是正式的解析入口了:

public Expression<T> ToLambdaExpression<T>()
{
    ProcessLambdaPrefix();
    var exp = ReadExpression();
 
    return LambdaExpression.Lambda<T>(exp.Expression, expParams);
}

这里要说明的是 expParams 参数,这个是用作 Lambda 表达式的参数必不可少的部分。ReadExpression 方法,递归调用解析 Lambda 表达式:

/// <summary>
/// Reads the expression.
/// </summary>
/// <param name="level">The level.</param>
/// <param name="wrapStart">The wrap start.</param>
/// <returns>The read result.</returns>
private ReadResult ReadExpression(int level = 0)
{
    var exp = ReadFirstExpression();
 
    //int nextLevel = 0;
    //var next = spResult.PeekNext();
    //while (!exp.IsClosedWrap &&
    //       (nextLevel = PriorityManager.GetOperatorLevel(next)) > level)
    //{
    //    exp = ReadNextExpression(nextLevel, exp, next.ID);
    //    next = spResult.PeekNext();
    //}
 
    return exp;
}
具体的 ReadFirstExpression 方法如下:
/// <summary>
/// Reads the first expression.
/// </summary>
/// <returns>The read result.</returns>
private ReadResult ReadFirstExpression()
{
    ReadResult result = ReadResult.Empty;
 
    var token = spResult.Next();
    switch (token.ID)
    {
        case TokenId.Identifier:
            result = ParseIdentifier(token);
            break;
        case TokenId.StringLiteral:
            if (token.Text.StartsWith("\""))
                result.Expression = Expression.Constant(token.Text.Substring(1, token.Text.Length - 2), typeof(string));
            else if (token.Text.StartsWith("'"))
                result.Expression = Expression.Constant(token.Text[1], typeof(char));
            break;
        case TokenId.IntegerLiteral:
            result.Expression = Expression.Constant(int.Parse(token.Text), typeof(int));
            break;
        case TokenId.LongIntegerLiteral:
            result.Expression = Expression.Constant(long.Parse(DeleteDigitTypeReference(token.Text)), typeof(long));
            break;
        case TokenId.RealLiteral:
            result.Expression = Expression.Constant(double.Parse(DeleteDigitTypeReference(token.Text)), typeof(double));
            break;
        case TokenId.SingleRealLiteral:
            result.Expression = Expression.Constant(float.Parse(DeleteDigitTypeReference(token.Text)), typeof(float));
            break;
        case TokenId.DecimalRealLiteral:
            result.Expression = Expression.Constant(decimal.Parse(DeleteDigitTypeReference(token.Text)), typeof(decimal));
            break;
        case TokenId.Exclamation:
            result.Expression = Expression.Not(ReadExpression().Expression);
            break;
        case TokenId.Plus:
        case TokenId.Comma:
            result = ReadExpression();
            break;
        case TokenId.Minus:
            result.Expression = Expression.Negate(ReadExpression().Expression);
            break;
        case TokenId.OpenParen:
            result = ParseConvertType();
            break;
        case TokenId.CloseParen:
        case TokenId.CloseBracket:
        case TokenId.CloseBrace:
            result.IsClosedWrap = true;
            break;
        default:
            throw new ParserSyntaxErrorException();
    }
 
    return result;
}
 
private ReadResult ParseIdentifier(Token token)
{
    ReadResult result = ReadResult.Empty;
 
    switch (token.Text)
    {
        case "true":
            result.Expression = Expression.Constant(true);
            break;
        case "false":
            result.Expression = Expression.Constant(false);
            break;
        case "null":
            result.Expression = Expression.Constant(null);
            break;
        case "sizeof":
            if (spResult.NextIs(TokenId.OpenParen))
            {
                result.Expression = Expression.Constant(Marshal.SizeOf(typeParser.ReadType()));
                spResult.NextIs(TokenId.CloseParen);
            }
            else
                throw new ParserSyntaxErrorException();
            break;
        case "typeof":
            if (spResult.NextIs(TokenId.OpenParen))
            {
                result.Expression = Expression.Constant(typeParser.ReadType(), typeof(Type));
                spResult.NextIs(TokenId.CloseParen);
 
            }
            else
                throw new ParserSyntaxErrorException();
            break;
        case "new":
            {
                var type = typeParser.ReadType();
 
                // 判断初始化的类型
                token = spResult.Next();
 
                // 构造函数成员初始化/集合项初始化
                if (token.ID == TokenId.OpenParen || token.ID == TokenId.OpenBrace)
                {
                    // 构建构造函数 new 的部分
                    if (token.ID == TokenId.OpenParen)
                    {
                        // 获取参数
                        var listParam = GetCollectionInits(true).ToArray();
                        var paramTypes = listParam.Select(m => m.Type).ToArray();
 
                        // 获取构造函数
                        var constructor = type.GetConstructors()
                            .Select(p => new
                            {
                                Parameters = p.GetParameters().Select(r => r.ParameterType).ToArray(),
                                Constructor = p,
                            })
                            .Where(p => p.Parameters.Length == paramTypes.Length)
                            .First(p => p.Parameters.Select(r => r.GetNoneNullableType())
                                                    .SequenceEqual(paramTypes.Select(r => r.GetNoneNullableType())))
                            .Constructor;
 
                        // 获取匹配的构造函数参数
                        var constructorParamTypes =
                            constructor.GetParameters()
                                        .Select(p => p.ParameterType)
                                        .Zip(listParam, (x, y) => new { Left = x, Right = y })
                                        .Select((p, i) =>
                                        {
                                            if (p.Left.IsNullable() && p.Left != p.Right.Type)
                                                return Expression.Convert(p.Right, p.Left.GetNullableType());
                                            else
                                                return p.Right;
                                        })
                                        .ToArray();
 
                        // 构造函数调用
                        result.Expression = Expression.New(constructor, constructorParamTypes);
                    }
                    else
                        result.Expression = Expression.New(type.GetConstructor(Type.EmptyTypes));
 
                    // 构建构造函数属性成员初始化或者集合初始化
                    if (spResult.PeekNextIs(TokenId.OpenBrace) || token.ID == TokenId.OpenBrace)
                    {
                        if (token.ID == TokenId.OpenParen)
                            spResult.Next();
 
                        // 测试是否属性成员初始化                            
                        bool isMemberInit = spResult.PeekNextIs(TokenId.Equal, 2);
 
                        if (isMemberInit)
                            result.Expression =
                                Expression.MemberInit((NewExpression)result.Expression, GetObjectMembers(type).ToArray());
                        else
                            result.Expression =
                                Expression.ListInit((NewExpression)result.Expression, GetCollectionInits().ToArray());
                    }
                }
                else if (token.ID == TokenId.OpenBracket)
                {
                    Expression[] @params = null;
                    if (spResult.PeekNextIs(TokenId.CloseBracket))
                        spResult.Next();
                    else
                        @params = GetCollectionInits().ToArray();
 
                    if (spResult.PeekNextIs(TokenId.OpenBrace))
                        result.Expression = Expression.NewArrayInit(type, GetCollectionInits().ToArray());
                    else
                        result.Expression = Expression.NewArrayBounds(type, @params);
                }
                else
                    throw new ParserSyntaxErrorException();
                break;
            }
        default:
            // 参数
            if (expParams.Any(p => p.Name == token.Text))
                result.Expression = expParams.First(p => p.Name == token.Text);
            // 类型
            else
            {
                var type = typeParser.ReadType(token.Text);
                spResult.NextIs(TokenId.Dot, true);
                var name = spResult.Next();
 
                // 跳过尖括号 <> 中的元素
                if (spResult.PeekNextIs(TokenId.LessThan))
                    spResult.SkipUntil(p => p.ID == TokenId.GreaterThan);
 
                if (spResult.PeekNextIs(TokenId.OpenParen))
                {
                    var @params = GetCollectionInits().ToArray();
                    var method = FindBestMethod(type, name, @params, true);
                    result.Expression = Expression.Call(method, @params);
                }
                else
                {
                    var member = type.GetMember(name)[0];
                    if (member.MemberType == MemberTypes.Property)
                        result.Expression = Expression.Property(null, (PropertyInfo)member);
                    else
                        result.Expression = Expression.Field(null, (FieldInfo)member);
                }
            }
            break;
    }
 
    return result;
}
 
private string DeleteDigitTypeReference(string number)
{
    if (char.IsLetter(number.Last()))
        return number.Substring(0, number.Length - 1);
    return number;
}
 
private ReadResult ParseConvertType()
{
    var originPos = spResult.Index;
    var type = typeParser.ReadType(ignoreException: true);
    if (type != null)
    {
        spResult.NextIs(TokenId.CloseParen, true);
        var inner = ReadExpression();
        return new ReadResult
        {
            Expression = Expression.Convert(inner.Expression, type),
            IsClosedWrap = inner.IsClosedWrap,
        };
    }
    else
    {
        spResult.ReturnToIndex(originPos);
        var result = ReadExpression();
        if (!spResult.PeekNextIs(TokenId.End))
            result.IsClosedWrap = false;
        return result;
    }
}

 

好了,这次就写到这里吧,下次把 ReadNextExpression 方法写出来,顺便也把整个的源码提供下载。没时间写了,不要说我不厚道,谢谢了!对了,补上 ReadResult 类的源码:

/// <summary>
/// 表达式读取结果
/// </summary>
[DebuggerStepThrough]
[DebuggerDisplay("IsClosedWrap = {IsClosedWrap}, Expression = {Expression}")]
public struct ReadResult
{
    private Expression _expression;
    private bool _isClosedWrap;
 
    /// <summary>
    /// 获取一个空的读取结果.
    /// </summary>
    public static ReadResult Empty
    {
        get { return new ReadResult(); }
    }
 
    /// <summary>
    /// 获取或设置读取到的表达式.
    /// </summary>
    public Expression Expression
    {
        get { return _expression; }
        set { _expression = value; }
    }
 
    /// <summary>
    /// 获取或设置一个值, 通过该值指示是否已经读取了关闭符号.
    /// </summary>
    public bool IsClosedWrap
    {
        get { return _isClosedWrap; }
        set { _isClosedWrap = value; }
    }
}

如果你感觉这篇文章对你有帮助,请帮忙点击一下推荐,谢谢了!

posted @ 2012-07-06 13:59  Lenic  阅读(3376)  评论(7编辑  收藏  举报