Is there an easy way to parse a (lambda expression) string into an Action delegate?

前端 未结 4 510
谎友^
谎友^ 2020-12-05 11:18

I have a method that alters an \"Account\" object based on the action delegate passed into it:

public static void AlterAccount(string AccountID, Action

        
相关标签:
4条回答
  • 2020-12-05 12:07

    That's easy:

    • Use CodeDom to generate the module containing the "surrounding class" you'll use to build the expression; this class must implement the interface known to your application
    • Use CodeSnippedExpression to inject the expression into its member.
    • Use Activator type to create the instance of this class in runtime.

    Basically, you need to build the following class with CodeDom:

    using System;
    using MyNamespace1;
    using ...
    using MyNamespace[N];
    
    namespace MyNamespace.GeneratedTypes 
    {
      public class ExpressionContainer[M] : IHasAccountAction
      {
        public Action<Account> AccountAction { 
          get {
            return [CodeSnippedExpression must be used here];
          }
        } 
      }
    }
    

    Assuming that IHasAccountAction is:

    public IHasAccountAction {
      public Action<Account> AccountAction { get; }
    }
    

    If this is done, you can get the expression compiled from string with ease. If you need its expression tree representation, use Expression<Action<Account>> instead of Action<Account> in generated type.

    0 讨论(0)
  • 2020-12-05 12:12

    There is no general way to parse a string into a lambda expression without a full compilation, because lambda expressions can reference things that are defined outside the lambda expression. I know of no library that handles the specific case you want. There's a long discussion of this on a thread on a C# discussion group.

    The easiest way to get what you want is to compile a method at runtime. You can write a function that takes in the string "a.Enabled = true; return a;" and sticks that in the middle of a function that takes an Account as a parameter. I would use this library as a starting point, but you can also use the function mentioned on another thread.

    0 讨论(0)
  • 2020-12-05 12:17

    You may try this: Dynamic Lambda Expressions Using An Isolated AppDomain

    It compiles a lambda expression using CodeDOM compiler. In order to dispose the in-memory assembly that gets created, the compiler runs on an isolated AppDomain. For the passing the expression through the domain boundary, it has to be serialized. Alas, Expression<> is not Serializable. So, a trick has to be used. All the details are explained in the post.

    I'm the author of that component, by the way. I would like very much to hear your feedback from it.

    0 讨论(0)
  • 2020-12-05 12:19

    The Dynamic LINQ library is a fine choice, as it'll generate expressions you can compile to code in a lightweight fashion.

    The example you provided actually produces a boolean -- so you should be able to ask for a Func and it might sort it out.

    Edit: This of course is wrong, as Expressions don't have assignment in them at all.

    So, another potential way is to take two lambdas. One to find the property you want, one to provide a value:

    (a => a.AccountId), (a => true)

    Then use reflection to set the property referenced in the first lambda with the result of the second one. Hackish, but it's still probably lightweight compared to invoking the C# compiler.

    This way you don't have to do much codegen yourself - the expressions you get will contain most everything you need.

    0 讨论(0)
提交回复
热议问题