Search code examples
c#.netcodedom

.Net CodeDom - Implement lambda expression in .net


I want to write something like this using CodeDom:

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

I don't know what is the equivalent of this in CodeDom (System.CodeDom).


Solution

  • Short answer: CodeDOM doesn't have any support for lambdas.

    Long answer: CodeDOM doesn't have any support for lambdas, so you will have to use a workaround. Some options:

    1. Use CodeSnippetExpression:

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

      This way, you lose most of the advantages of using CodeDOM, but it's easy and you can do exactly what you want.

    2. Create a method containing code from the lambda and then use a delegate referencing it:

      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"))
      

      This generates code like:

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

      The issues with this approach is that it generates different (and less readable) code than what you wanted and that it won't work if the query has to be an expression, usually because you're using IQueryable<T> with something like Entity Framework.

    3. Switch to a code generation library that supports lambdas, like 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))))))))
      

      Or using 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))))
      

      The obvious disadvantage here is that you will have to rewrite your code.