¿Cómo puedo evaluar el código de C # de forma dinámica?

Puedo hacer una eval("something()"); para ejecutar el código dinámicamente en JavaScript. ¿Hay alguna forma de que haga lo mismo en C #?

Un ejemplo de lo que estoy tratando de hacer es: Tengo una variable entera (digamos i ) y tengo varias propiedades por los nombres: “Propiedad1”, “Propiedad2”, “Propiedad3”, etc. Ahora, quiero realizar algunas operaciones en la propiedad “Propiedad i ” dependiendo del valor de i .

Esto es realmente simple con Javascript. ¿Hay alguna manera de hacer esto con C #?

Desafortunadamente, C # no es un lenguaje dynamic como ese.

Sin embargo, lo que puede hacer es crear un archivo de código fuente de C #, lleno de clase y todo, y ejecutarlo a través del proveedor de CodeDom para C # y comstackrlo en un ensamblaje, y luego ejecutarlo.

Esta publicación del foro en MSDN contiene una respuesta con algún código de ejemplo en la página:
crear un método anónimo de una cadena?

Difícilmente diría que esta es una muy buena solución, pero de todos modos es posible.

¿Qué tipo de código esperas en esa cadena? Si se trata de un subconjunto menor de código válido, por ejemplo solo expresiones matemáticas, es posible que existan otras alternativas.


Editar : Bueno, eso me enseña a leer las preguntas completamente primero. Sí, la reflexión podría ayudarte aquí.

Si divide la cadena por el; primero, para obtener propiedades individuales, puede usar el siguiente código para obtener un objeto PropertyInfo para una propiedad en particular para una clase, y luego usar ese objeto para manipular un objeto en particular.

 String propName = "Text"; PropertyInfo pi = someObject.GetType().GetProperty(propName); pi.SetValue(someObject, "New Value", new Object[0]); 

Enlace: Método PropertyInfo.SetValue

Realmente no. Puede usar el reflection para lograr lo que quiere, pero no será tan simple como en Javascript. Por ejemplo, si desea establecer el campo privado de un objeto en algo, puede usar esta función:

 protected static void SetField(object o, string fieldName, object value) { FieldInfo field = o.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic); field.SetValue(o, value); } 

Usando la API de scripting de Roslyn (más ejemplos aquí ):

 // add NuGet package 'Microsoft.CodeAnalysis.Scripting' using Microsoft.CodeAnalysis.CSharp.Scripting; await CSharpScript.EvaluateAsync("System.Math.Pow(2, 4)") // returns 16 

También puedes ejecutar cualquier código:

 var script = await CSharpScript.RunAsync(@" class MyClass { public void Print() => System.Console.WriteLine(1); }") 

Y haga referencia al código que se generó en las ejecuciones anteriores:

 await script.ContinueWithAsync("new MyClass().Print();"); 

Todo eso definitivamente funcionaría. Personalmente, para ese problema en particular, probablemente tomaría un enfoque diferente. Tal vez algo como esto:

 class MyClass { public Point point1, point2, point3; private Point[] points; public MyClass() { //... this.points = new Point[] {point1, point2, point3}; } public void DoSomethingWith(int i) { Point target = this.points[i+1]; // do stuff to target } } 

Al usar patrones como este, debe tener cuidado de que sus datos se almacenen por referencia y no por valor. En otras palabras, no hagas esto con primitivos. Tienes que usar sus contrapartes de la clase hinchada grandes.

Me di cuenta de que esa no era exactamente la pregunta, pero la pregunta se había respondido bastante bien y pensé que tal vez un enfoque alternativo podría ayudar.

Esta es una función eval bajo c #. Lo usé para convertir funciones anónimas (Lambda Expressions) de una cadena. Fuente: http://www.codeproject.com/KB/cs/evalcscode.aspx

 public static object Eval(string sCSCode) { CSharpCodeProvider c = new CSharpCodeProvider(); ICodeCompiler icc = c.CreateCompiler(); CompilerParameters cp = new CompilerParameters(); cp.ReferencedAssemblies.Add("system.dll"); cp.ReferencedAssemblies.Add("system.xml.dll"); cp.ReferencedAssemblies.Add("system.data.dll"); cp.ReferencedAssemblies.Add("system.windows.forms.dll"); cp.ReferencedAssemblies.Add("system.drawing.dll"); cp.CompilerOptions = "/t:library"; cp.GenerateInMemory = true; StringBuilder sb = new StringBuilder(""); sb.Append("using System;\n" ); sb.Append("using System.Xml;\n"); sb.Append("using System.Data;\n"); sb.Append("using System.Data.SqlClient;\n"); sb.Append("using System.Windows.Forms;\n"); sb.Append("using System.Drawing;\n"); sb.Append("namespace CSCodeEvaler{ \n"); sb.Append("public class CSCodeEvaler{ \n"); sb.Append("public object EvalCode(){\n"); sb.Append("return "+sCSCode+"; \n"); sb.Append("} \n"); sb.Append("} \n"); sb.Append("}\n"); CompilerResults cr = icc.CompileAssemblyFromSource(cp, sb.ToString()); if( cr.Errors.Count > 0 ){ MessageBox.Show("ERROR: " + cr.Errors[0].ErrorText, "Error evaluating cs code", MessageBoxButtons.OK, MessageBoxIcon.Error ); return null; } System.Reflection.Assembly a = cr.CompiledAssembly; object o = a.CreateInstance("CSCodeEvaler.CSCodeEvaler"); Type t = o.GetType(); MethodInfo mi = t.GetMethod("EvalCode"); object s = mi.Invoke(o, null); return s; } 

He escrito un proyecto de código abierto, Dynamic Expresso , que puede convertir expresiones de texto escritas utilizando una syntax de C # en delegates (o árbol de expresiones). Las expresiones se analizan y se transforman en Expression Trees sin usar comstackción o reflexión.

Puedes escribir algo como:

 var interpreter = new Interpreter(); var result = interpreter.Eval("8 / 2 + 2"); 

o

 var interpreter = new Interpreter() .SetVariable("service", new ServiceExample()); string expression = "x > 4 ? service.SomeMethod() : service.AnotherMethod()"; Lambda parsedExpression = interpreter.Parse(expression, new Parameter("x", typeof(int))); parsedExpression.Invoke(5); 

Mi trabajo se basa en el artículo de Scott Gu http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx .

No quiero ahora si quieres ejecutar sentencias C #, pero ya puedes ejecutar sentencias Javascript en C # 2.0. La biblioteca de código abierto Jint es capaz de hacerlo. Es un intérprete de Javascript para .NET. Pase un progtwig Javascript y se ejecutará dentro de su aplicación. Incluso puede pasar el objeto C # como argumentos y automatizarlo.

Además, si solo desea evaluar la expresión de sus propiedades, pruebe NCalc .

Puede usar el reflection para obtener la propiedad e invocarla. Algo como esto:

 object result = theObject.GetType().GetProperty("Property" + i).GetValue(theObject, null); 

Es decir, suponiendo que el objeto que tiene la propiedad se llama “theObject” 🙂

También podría implementar un Webbrowser, luego cargar un archivo html que contenga javascript.

Luego vaya por el document.InvokeScript InvokeScript Method en este navegador. El valor de retorno de la función eval se puede atrapar y convertir en todo lo que necesita.

Hice esto en varios proyectos y funciona perfectamente.

Espero eso ayude

Podrías hacerlo con una función de prototipo:

 void something(int i, string P1) { something(i, P1, String.Empty); } void something(int i, string P1, string P2) { something(i, P1, P2, String.Empty); } void something(int i, string P1, string P2, string P3) { something(i, P1, P2, P3, String.Empty); } 

y así…

Utiliza la reflexión para analizar y evaluar una expresión de enlace de datos contra un objeto en tiempo de ejecución.

Método DataBinder.Eval

He escrito un paquete, SharpByte.Dynamic , para simplificar la tarea de comstackr y ejecutar código dinámicamente. El código se puede invocar en cualquier objeto de contexto usando métodos de extensión como se detalla aquí .

Por ejemplo,

 someObject.Evaluate("6 / {{{0}}}", 3)) 

devuelve 3;

 someObject.Evaluate("this.ToString()")) 

devuelve la representación de cadena del objeto de contexto;

 someObject.Execute(@ "Console.WriteLine(""Hello, world!""); Console.WriteLine(""This demonstrates running a simple script""); "); 

ejecuta esas declaraciones como un script, etc.

Los ejecutables se pueden obtener fácilmente utilizando un método de fábrica, como se ve en el ejemplo aquí; todo lo que necesita es el código fuente y la lista de los parámetros con nombre esperados (los tokens se incrustan utilizando la notación de triple corchete, como {{{0}} }, para evitar colisiones con string.Format () así como con syntax tipo Handlebars):

 IExecutable executable = ExecutableFactory.Default.GetExecutable(executableType, sourceCode, parameterNames, addedNamespaces); 

Cada objeto ejecutable (script o expresión) es seguro para subprocesos, puede almacenarse y reutilizarse, admite el registro desde un script, almacena información de tiempo y última excepción si se encuentra, etc. También hay un método Copy () comstackdo en cada uno para permitir creando copias baratas, es decir, utilizando un objeto ejecutable comstackdo a partir de un script o expresión como plantilla para crear otros.

La sobrecarga de la ejecución de una secuencia de comandos o una secuencia de comandos ya comstackda es relativamente baja, muy por debajo de un microsegundo en hardware modesto, y las secuencias de comandos y expresiones ya comstackdas se almacenan en caché para su reutilización.

Estaba tratando de obtener el valor de un miembro de estructura (clase) por su nombre. La estructura no era dinámica. Todas las respuestas no funcionaron hasta que finalmente lo obtuve:

 public static object GetPropertyValue(object instance, string memberName) { return instance.GetType().GetField(memberName).GetValue(instance); } 

Este método devolverá el valor del miembro por su nombre. Funciona en una estructura regular (clase).

Puede consultar la biblioteca Heleonix.Reflection . Proporciona métodos para obtener / configurar / invocar miembros dinámicamente, incluidos los miembros nesteds, o si un miembro está claramente definido, puede crear un getter / setter (lambda comstackdo en un delegado) que es más rápido que la reflexión:

 var success = Reflector.Set(instance, null, $"Property{i}", value); 

O si el número de propiedades no es infinito, puede generar setters y chachearlas (los setters son más rápidos ya que son delegates comstackdos):

 var setter = Reflector.CreateSetter($"Property{i}", typeof(type which contains "Property"+i)); setter(instance, value); 

Los organismos de seguridad pueden ser de tipo Action pero las instancias pueden ser diferentes en el tiempo de ejecución, por lo que puede crear listas de instaladores.

Desafortunadamente, C # no tiene instalaciones nativas para hacer exactamente lo que estás pidiendo.

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

la respuesta correcta es que debe almacenar en caché todo el resultado para mantener bajo el uso de memoria.

un ejemplo se vería así

 TypeOf(Evaluate) { "1+1":2; "1+2":3; "1+3":5; .... "2-5":-3; "0+0":1 } 

y agregarlo a una lista

 List results = new List(); for() results.Add(result); 

guarda la identificación y úsala en el código

espero que esto ayude