.Net CodeDom - 在 .net 中实现 lambda 表达式

.Net CodeDom - Implement lambda expression in .net

我想用 CodeDom 写这样的东西:

.Where(x => x.Id == 2);

我不知道 CodeDom (System.CodeDom) 中的这个等价物是什么。

简答:CodeDOM 不支持 lambda。

长答案:CodeDOM 不支持 lambda,因此您必须使用变通方法。部分选项:

  1. 使用CodeSnippetExpression:

    new CodeMethodInvokeExpression(
        collectionExpression, "Where", new CodeSnippetExpression("x => x.Id == 2"));
    

    这样,您将失去使用 CodeDOM 的大部分优势,但它很简单,您可以完全按照自己的意愿行事。

  2. 创建一个包含来自 lambda 的代码的方法,然后使用引用它的委托:

    var lambdaMethod = new CodeMemberMethod
    {
        Name = "IsIdTwo",
        Parameters =
        {
            new CodeParameterDeclarationExpression(
                new CodeTypeReference("YourEntityType"), "x")
        },
        Statements =
        {
            new CodeMethodReturnStatement(
                new CodeBinaryOperatorExpression(
                    new CodePropertyReferenceExpression(
                        new CodeVariableReferenceExpression("x"), "Id"),
                    CodeBinaryOperatorType.ValueEquality,
                    new CodePrimitiveExpression(2)))
        }
    };
    
    …
    
    new CodeMethodInvokeExpression(
        collectionExpression, "Where", new CodeMethodReferenceExpression(null, "IsIdTwo"))
    

    这会生成如下代码:

    private void IsIdTwo(YourEntityType x) {
        return (x.Id == 2);
    }
    
    …
    
    collection.Where(IsIdTwo)
    

    这种方法的问题是它生成的代码与您想要的不同(且可读性较差),如果查询必须是表达式,它就无法工作,通常是因为您使用的是 IQueryable<T> 类似 Entity Framework.

  3. 切换到支持 lambda 的代码生成库,例如 Roslyn:

    using Microsoft.CodeAnalysis;
    using Microsoft.CodeAnalysis.CSharp;
    using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
    
    …
    
    InvocationExpression(
        MemberAccessExpression(
            SyntaxKind.SimpleMemberAccessExpression,
            IdentifierName("collection"),
            IdentifierName("Where")),
        ArgumentList(
            SingletonSeparatedList(
                Argument(
                    SimpleLambdaExpression(
                        Parameter(Identifier("x")),
                        BinaryExpression(
                            SyntaxKind.EqualsExpression,
                            MemberAccessExpression(
                                SyntaxKind.SimpleMemberAccessExpression,
                                IdentifierName("x"),
                                IdentifierName("Id")),
                            LiteralExpression(
                                SyntaxKind.NumericLiteralExpression, Literal(2))))))))
    

    或使用SyntaxGenerator:

    var generator = SyntaxGenerator.GetGenerator(new AdhocWorkspace(), LanguageNames.CSharp);
    
    generator.InvocationExpression(
        generator.MemberAccessExpression(generator.IdentifierName("collection"), "Where"),
        generator.ValueReturningLambdaExpression(
            "x",
            generator.ValueEqualsExpression(
                generator.MemberAccessExpression(generator.IdentifierName("x"), "Id"),
                generator.LiteralExpression(2))))
    

    这里明显的缺点是您将不得不重写代码。