108 votes

Comment puis-je évaluer le code C# de manière dynamique ?

Je peux faire un eval("something()"); pour exécuter le code dynamiquement en JavaScript. Existe-t-il un moyen pour moi de faire la même chose en C# ?

Voici un exemple de ce que j'essaie de faire : J'ai une variable entière (disons i ) et j'ai plusieurs propriétés dont les noms sont : "Propriété1", "Propriété2", "Propriété3", etc. Maintenant, je veux effectuer des opérations sur la " propriété ". i "selon la valeur de la propriété i .

C'est très simple avec Javascript. Y a-t-il un moyen de le faire avec C# ?

0 votes

3 votes

C# appelle l'eval de ironpython. Je l'ai essayé en c# 4.0. Je n'ai aucune expérience en c# 2.0.

0 votes

@Peter Long, où puis-je trouver de la documentation sur l'évaluation d'IronPython ?

50voto

Lasse V. Karlsen Points 148037

Malheureusement, le C# n'est pas un langage dynamique comme celui-là.

Ce que vous pouvez faire, cependant, c'est créer un fichier de code source C#, avec des classes et tout le reste, et le faire passer par le fournisseur CodeDom pour C#, le compiler dans une assemblée, puis l'exécuter.

Ce post de forum sur MSDN contient une réponse avec un code d'exemple un peu plus bas sur la page :
créer une méthode anonyme à partir d'une chaîne de caractères ?

Je ne dirais pas que c'est une très bonne solution, mais c'est quand même possible.

Quel genre de code allez-vous attendre dans cette chaîne ? S'il s'agit d'un sous-ensemble mineur de code valide, par exemple juste des expressions mathématiques, il se peut que d'autres alternatives existent.


Modifier : Eh bien, cela m'apprend à lire attentivement les questions d'abord. Oui, la réflexion pourrait vous aider ici.

Si vous divisez d'abord la chaîne de caractères par le caractère ;, pour obtenir les propriétés individuelles, vous pouvez utiliser le code suivant pour obtenir un objet PropertyInfo pour une propriété particulière d'une classe, puis utiliser cet objet pour manipuler un objet particulier.

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

Lien : Méthode PropertyInfo.SetValue

0 votes

Que se passe-t-il si GetProperty doit être une fonction avec des paramètres x,y ?, c'est-à-dire Text(1,2) ?

0 votes

@user1735921 Ensuite, vous devrez utiliser GetMethod(methodName) à la place, analyser les valeurs des paramètres, et appeler la méthode en utilisant la réflexion.

0 votes

Typeof(ObjectType) est analogue à someObject.GetType()

14voto

Karl Seguin Points 10566

Pas vraiment. Vous pouvez utiliser la réflexion pour obtenir ce que vous voulez, mais ce ne sera pas aussi simple qu'en Javascript. Par exemple, si vous vouliez donner une valeur au champ privé d'un objet, vous pourriez utiliser cette fonction :

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

13voto

Largo Points 71

Il s'agit d'une fonction eval sous c#. Je l'ai utilisée pour convertir des fonctions anonymes (Lambda Expressions) à partir d'une chaîne de caractères. Source : 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;

}

3 votes

Oups, j'ai corrigé la faute de frappe (Lambada => Lambda). Je ne savais pas que la chanson s'appelait Lambada donc celle-ci n'était pas intentionnelle. ;)

0 votes

Je ne comprends pas pourquoi cette réponse a reçu moins de votes. Elle est très utile.

7voto

MojoFilter Points 3730

Tout cela pourrait certainement fonctionner. Personnellement, pour ce problème particulier, j'adopterais probablement une approche un peu différente. Peut-être quelque chose comme ça :

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
  }
}

Lorsque vous utilisez des modèles de ce type, vous devez veiller à ce que vos données soient stockées par référence et non par valeur. En d'autres termes, ne faites pas cela avec des primitives. Vous devez utiliser leurs équivalents de classe gonflés.

Je me suis rendu compte que ce n'est pas exactement la question, mais la question a été assez bien répondue et j'ai pensé qu'une approche alternative pourrait être utile.

5voto

Je ne sais pas maintenant si vous voulez absolument exécuter des instructions C#, mais vous pouvez déjà exécuter des instructions Javascript dans C# 2.0. La bibliothèque open-source Jint est capable de le faire. Il s'agit d'un interprète Javascript pour .NET. Passez un programme Javascript et il s'exécutera dans votre application. Vous pouvez même passer des objets C# comme arguments et faire de l'automatisation sur eux.

De même, si vous souhaitez simplement évaluer une expression sur vos propriétés, essayez la méthode NCalc .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X