c# array ¿Hay alguna forma de ejecutar dinámicamente una cadena en.net, similar a eval() en javascript o sql dinámico en sql?



eval php (7)

No es demasiado difícil;) Puse un pequeño ejemplo. Esto debería ayudarlo a decidir si desea usar scripts dinámicos ... o expresiones regulares.

Lo que puede hacer es crear una interfaz en su ensamblaje, que implementará su código dinámico:

namespace CompileScriptExample
{
  public interface IStringManipulator
  {
    string processString(string aString);
  }
}

Luego crea una clase ScriptRunner:

namespace CompileScriptExample
{ 
public class ScriptRunner
{

    public static string RunScript(string scriptCode, string scriptParameter)
    {

        CodeDomProvider provider = new Microsoft.CSharp.CSharpCodeProvider();

        //configure parameters
        CompilerParameters parameters = new CompilerParameters();
        parameters.GenerateExecutable = false;
        parameters.GenerateInMemory = true;
        parameters.IncludeDebugInformation = false;
        string reference;
        // Set reference to current assembly - this reference is a hack for the example..
        reference = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
        parameters.ReferencedAssemblies.Add(reference+"\\CompileScriptExample.exe");

        //compile
        CompilerResults results = provider.CompileAssemblyFromSource(parameters, new string[] { scriptCode });

        if (results.Errors.Count == 0)
        {
            IStringManipulator compiledScript=(IStringManipulator)FindInterface(results.CompiledAssembly, "IStringManipulator");
            return compiledScript.processString(scriptParameter);//run the script, pass the string param..
        }
        else
        {
            foreach(CompilerError anError in results.Errors)
            {
                MessageBox.Show(anError.ErrorText);
            }
            //handle compilation errors here
            //..use results.errors collection
            throw new Exception("Compilation error...");
        }
    }

    private static object FindInterface(Assembly anAssembly, string interfaceName)
    {
        // find our interface type..
        foreach (Type aType in anAssembly.GetTypes())
        {
            if (aType.GetInterface(interfaceName, true) != null)
                return anAssembly.CreateInstance(aType.FullName);
        }
        return null;
    }
}

}

Ahora todo lo que tiene que hacer es crear una secuencia de comandos con código que implemente su interfaz como ...

string myScriptString=@"using CompileScriptExample;
public class MyStringManipulator : IStringManipulator
{
  public string processString(string aString)
  {
        return aString+aString;
  }
};

y luego ... en su código, use ScriptRunner para procesar su cadena con su código dinámico:

string processedString = ScriptRunner.RunScript(myScriptString, "hello");

¿Hay alguna forma de ejecutar dinámicamente el código contenido en una cadena utilizando .net 2.0, de forma similar a eval () en javascript o utilizando sp_executeSQL en tsql?

Tengo un valor de cadena en una variable que quiero manipular en algún momento de mi aplicación, por lo que el código sería esencialmente manipulación de cadenas. No sé qué se necesitarán diferentes manipulaciones, así que me gustaría que sean configurables.

Realmente no me importa en qué idioma esté escrito el código dinámico, lo que sea más fácil de implementar y lo suficientemente simple para escribir.

Por ejemplo, podría querer reemplazar instancias de '.' caracter con '-', o quitar todos los espacios, o similar. Si estuviera haciendo esto en sql usaría sql dinámico, pero quiero ejecutarlo en código .net, algo como esto:

// Get the value to be manipulated
string s = ... // wherever s comes from

// Get the manipulation code, eg this might come from a database 
// setting that can be changed without recompiling the .net code.
string manipulation = Settings.GetSomeValue("ManipulationSetting");

// This is what I want to know how to do: apply some manipulation to the string.
string result = MagicDynamicEvalClass.Eval(manipulation, s);

// Now I would do stuff with the result.

Posiblemente podría usar expresiones de búsqueda / reemplazo de expresiones regulares. Como todo lo que hago es manipulación de cadenas, esto debería ser suficiente siempre que pueda escribir expresiones regulares suficientemente inteligentes. p.ej:

// Get the value to be manipulated
string s = ... // wherever s comes from

// Get the code to use to manipulate s, eg this might come from a database 
// setting that can be changed without recompiling the .net code.
string findRegex = Settings.GetSomeValue("RegexPattern");
string replaceRegex = Settings.GetSomeValue("RegexReplace");

// This is what I want to know how to do: apply some manipulation to the string.
string result = Regex.Replace(s, findRegex, replaceRegex);

// Now I can do stuff with the result.

Pero en algunos casos mi requisito de manipulación puede exceder lo que es posible con expresiones regulares, o tal vez quiera aplicar varios pasos, por ejemplo, reemplazar '.' con '-' y también espacios de tira. Quizás podría almacenar una lista de expresiones regulares para buscar / reemplazar e iterar sobre ellas ... pero ¿alguien tiene una mejor sugerencia?

ACTUALIZACIÓN - ejemplo usando sql dinámico

No quiero una solución que me obligue a saber de antemano qué manipulaciones son posibles, y realmente estoy buscando algo simple. por ejemplo, en sql haría algo como esto:

declare @s nvarchar(1000)
declare @manipulation nvarchar(1000)
declare @result nvarchar(1000)

-- ... Get the values from wherever they come from

-- Execute the manipulation dynamically
EXEC sp_ExecuteSQL @stmt = @manipulation
    , @params = N'@s nvarchar(1000), @result nvarchar(1000) OUTPUT'
    , @s = @s, @result = @result OUTPUT

Entonces podría poner sql arbitrario en mi @manipulación, algo como esto SET @result = REPLACE (@s, '.', '-'), '', '')

Sí, esto requeriría que tuviera cuidado sobre qué valores se pueden poner en @manipulación, pero me daría la flexibilidad que necesito en el futuro.

Un enfoque similar sería posible en JavaScript, supongo, usando eval ().

ACTUALIZACIÓN - ejemplo que usa control de MSScript desde .net:

Este parece ser un enfoque posible, aunque quizás demasiado para el caso simple que quiero tratar. Utiliza la biblioteca Microsoft Script Control para permitir la ejecución de VBScript arbitrario.


Answer #1

Si bien podría usar una enumeración para indicar la acción que desea tomar, o usar CodeDom para emitir código de manera dinámica, lo que se necesita es definir una transformación de algún tipo, lo que significa que tiene entradas y una salida. .

Averiguar la salida es fácil en este caso, tiene una cadena. Para las entradas, parece que puede tener un número variable de entradas. Eso se definiría como una IEnumerable<string> .

Con eso en mente, puede definir una interfaz como esta:

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

Entonces, sería fácil definir implementaciones de este tipo y luego colocar los nombres de tipo en su configuración.

Realmente desea hacer esto en lugar de compilar dinámicamente código de cadenas. Al usar strings, tiene una gran flexibilidad, sí, pero no tiene tiempo de compilación y se está abriendo a errores y problemas de seguridad.

Además, el tiempo que llevará escribir un fragmento de código para emitir código basado en el fragmento de cadena que proporciones también será bastante tedioso, ya que tienes que construir el ensamblaje, la clase, el método y luego compilar , y luego invoque el método que compila dinámicamente a través de la reflexión (a menos que tenga que implementar una interfaz, en cuyo caso, también puede hacer lo que estoy sugiriendo de todos modos).


Answer #2

Creo que es posible usar reflection.emit y codificado para hacer esto, pero no es en absoluto trivial y aconsejo que no lo haga.

Como alternativa, puede intentar configurar una cadena de formato, posiblemente además de la expresión regular.



Answer #4

El otro día me encontré con algo que hace esto en otro lenguaje .NET: http://reverseblade.blogspot.com/2009/02/dont-wait-for-c-5-use-nemerle.html

Me imagino que podría escribir su código de procesamiento de cadenas en nemerle, compilar y referenciar desde su aplicación C # o VB.

Aún así, preferiría un diseño extensible como CasperOne sugiere. Al hacer scripts dinámicos, solo estará empujando la compilación en la aplicación y la implementación en cualquier proceso que obtenga las cadenas de programación para la aplicación. Pero parece que tienes tus razones, entonces la única otra cosa que consideraría aquí es la seguridad. Lo ideal es que limites al usuario tanto como sea posible a solo manipular cadenas, en cuyo caso List-of-Regex parece ser una buena opción.


Answer #5

Sé que buscas C # pero el código que tengo para esto está en VB. Podrías traducirlo fácilmente usando el convertidor de VB a C # de Developer Fusion. Lo usé en un proyecto para permitir a los usuarios agregar cálculos complejos en su aplicación en tiempo de ejecución. Compila su código VB en una biblioteca en memoria y luego ejecuta el código devolviendo la salida resultante. Podría ser reutilizado con bastante facilidad para lo que estás tratando de hacer.

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

Configuré mi código dinámico así:

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"

Y luego configura algunos argumentos para la expresión y ejecuta:

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

Answer #6

No hay un método incorporado de C # para llamar a eval () en tiempo de ejecución.

Sin embargo, mi programa de evaluación de C # permite evaluar el código de C #. Proporciona la evaluación del código C # en tiempo de ejecución y admite muchas sentencias C #. De hecho, este código se puede utilizar en cualquier proyecto .NET, sin embargo, está limitado a usar la sintaxis C #. Eche un vistazo a mi sitio web, http://csharp-eval.com , para obtener detalles adicionales.





dynamic