Is there a way to dynamically execute a string in .net, similar to eval() in javascript or dynamic sql in sql?

前端 未结 8 1415
心在旅途
心在旅途 2020-12-05 12:39

Is there a way to dynamically execute code contained in a string using .net 2.0, in a similar way to eval() in javascript or using sp_executeSQL in tsql?

I have a st

相关标签:
8条回答
  • 2020-12-05 13:03

    I think it's possible using reflection.emit and codedom to do this, but it's not at all trivial and I advise against it.

    As an alternative, you could try configuring a format string, possibly in addition to the regex.

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

    I know you're after C# but the code I have for this is in VB. You could translate it easily enough using Developer Fusion's VB to C# converter. I used it on a project to allow users to add complex calculations into their application at runtime. It compiles their VB code into a library in memory and then runs the code returning the resulting output. It could be repurposed fairly easily for what you're attempting to do.

    Imports System.Reflection
    Imports System.CodeDom.Compiler
    Imports System.Text.RegularExpressions
    Imports System.Math
    
    Module Module1
    
      Function Evaluate(ByVal Expression As String, ByVal Args() As Object) As Object
    
        If Expression.Length > 0 Then
    
            'Replace each parameter in the calculation expression with the correct values
            Dim MatchStr = "{(\d+)}"
            Dim oMatches = Regex.Matches(Expression, MatchStr)
            If oMatches.Count > 0 Then
                Dim DistinctCount = (From m In oMatches _
                                     Select m.Value).Distinct.Count
                If DistinctCount = Args.Length Then
                    For i = 0 To Args.Length - 1
                        Expression = Expression.Replace("{" & i & "}", Args(i))
                    Next
                Else
                    Throw New ArgumentException("Invalid number of parameters passed")
                End If
            End If
    
            Dim FuncName As String = "Eval" & Guid.NewGuid.ToString("N")
            Dim FuncString As String = "Imports System.Math" & vbCrLf & _
                                       "Namespace EvaluatorLibrary" & vbCrLf & _
                                       "  Class Evaluators" & vbCrLf & _
                                       "    Public Shared Function " & FuncName & "() As Double" & vbCrLf & _
                                       "      " & Expression & vbCrLf & _
                                       "    End Function" & vbCrLf & _
                                       "  End Class" & vbCrLf & _
                                       "End Namespace"
    
            'Tell the compiler what language was used
            Dim CodeProvider As CodeDomProvider = CodeDomProvider.CreateProvider("VB")
    
            'Set up our compiler options...
            Dim CompilerOptions As New CompilerParameters()
            With CompilerOptions
                .ReferencedAssemblies.Add("System.dll")
                .GenerateInMemory = True
                .TreatWarningsAsErrors = True
            End With
    
            'Compile the code that is to be evaluated
            Dim Results As CompilerResults = _
                CodeProvider.CompileAssemblyFromSource(CompilerOptions, FuncString)
    
            'Check there were no errors...
            If Results.Errors.Count > 0 Then
            Else
                'Run the code and return the value...
                Dim dynamicType As Type = Results.CompiledAssembly.GetType("EvaluatorLibrary.Evaluators")
                Dim methodInfo As MethodInfo = dynamicType.GetMethod(FuncName)
                Return methodInfo.Invoke(Nothing, Nothing)
            End If
    
        Else
            Return 0
    
        End If
    
        Return 0
    
      End Function
    
    End Module
    

    I set up my dynamic code like this:

    Dim Expr As String = "  If ({0} < 20000) Then" & vbCrLf & _
                         "    Return Max(15, Min(75,0.12*{0}))" & vbCrLf & _
                         "  Else" & vbCrLf & _
                         "    Return Max(75,0.05*{0})" & vbCrLf & _
                         "  End If"
    

    And then set up some arguments for the expression and execute:

    Dim Args As New List(Of String)
    While True
        Dim Val As String = Console.ReadLine
        Args.Clear()
        If IsNumeric(Val) Then
            Args.Add(Val)
            Dim dblOut As Object = Evaluate(Expr, Args.ToArray)
            Console.WriteLine(dblOut)
        Else
            Exit While
        End If
    End While
    
    0 讨论(0)
  • 2020-12-05 13:08

    like the others already mentioned its not really possible to compile c# in an eval() function. that functionality is planed for a latter release of the clr which anders demoed at the PDC.

    as a diffrent solutionm, if your application is able to run on mono you can just use its eval function which can dynamicly compile c# code, just like javascript. it is basicly already doing what .net will be able to do in a year or two.

    as an alternative if you cant use mono you could write the part that does the string manipulation in ironruby which has eval(). the rest of your code wont even know you are using ruby for that class/assambly.

    the link you posted in the update looks pretty complicated for such a simple use case. using ironruby all you would have to do is write the MyDynamicEvalClass something like this:

    class MyDynamicEvalClass
      def eval(someString,transformString)
        eval(someString,transformString)
      end
    end
    

    and replacing "ManipulationSetting" with some ruby code that returns a new string

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

    How about my solution for Eval

    how to execute string path on dynamic type?

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

    While you could use an enumeration to indicate the action you want to take, or use CodeDom to emit code dynamically, what it comes down to is that you want to define a transformation of some kind, which means that you have inputs, and an output.

    Figuring out the output is easy in this case, you have a string. For the inputs, it would seem like you can have a variable number of inputs. That would be defined as an IEnumerable<string>.

    With that in mind, you can define an interface like so:

    public interface IStringManipulation
    {
      string Manipulate(IEnumerable<string> parameters);
    }
    

    Then, it would be easy to define implementations of this type and then place the type names in your config.

    You really want to do this instead of dynamically compiling code from strings. In using strings, you have a great deal of flexibility, yes, but you have no compile time checking, and are opening yourself up to bugs and security issues.

    Also, the time it is going to take to write a piece of code to emit code based on the string fragment you provide is going to be quite tedious as well, as you have to build the assembly, the class, the method, then compile, and then call the method you compile dynamically through reflection (unless you have it implement an interface, in which case, you might as well do what I'm suggesting anyways).

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

    There is no C# built-in method for calling eval() at runtime.

    However, my C# eval program does allow for evaluating C# code. It provides for evaluating C# code at runtime and supports many C# statements. In fact, this code is usable within any .NET project, however, it is limited to using C# syntax. Have a look at my website, http://csharp-eval.com, for additional details.

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