Question

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# ?

Un exemple de ce que j'essaie de faire est :J'ai une variable entière (disons i) et j'ai plusieurs propriétés portant les noms :"Propriété1", "Propriété2", "Propriété3", etc.Maintenant, je souhaite effectuer quelques opérations sur la " Propriétéje " propriété en fonction de la valeur de i.

C'est vraiment simple avec Javascript.Existe-t-il un moyen de faire cela avec C# ?

Était-ce utile?

La solution

Malheureusement, 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#, rempli de classe et tout, et l'exécuter via le fournisseur CodeDom pour C# et le compiler dans un assembly, puis l'exécuter.

Ce message du forum sur MSDN contient une réponse avec un exemple de code en bas de la page :
créer une méthode anonyme à partir d'une chaîne ?

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

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


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

Si vous divisez la chaîne par le ;Tout d'abord, pour obtenir des 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

Autres conseils

Utilisation de l'API de script Roslyn (plus des échantillons ici):

// add NuGet package 'Microsoft.CodeAnalysis.Scripting'
using Microsoft.CodeAnalysis.CSharp.Scripting;

await CSharpScript.EvaluateAsync("System.Math.Pow(2, 4)") // returns 16

Vous pouvez également exécuter n'importe quel morceau de code :

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

Et référencez le code généré lors des exécutions précédentes :

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

Pas vraiment.Vous pouvez utiliser la réflexion pour réaliser ce que vous voulez, mais ce ne sera pas aussi simple qu'en Javascript.Par exemple, si vous souhaitez définir le champ privé d'un objet sur quelque chose, vous pouvez 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);
}

Il s'agit d'une fonction d'évaluation sous c#.Je l'ai utilisé pour convertir des fonctions anonymes (expressions Lambda) à partir d'une chaîne.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;

}

J'ai écrit un projet open source, Expresso dynamique, qui peut convertir une expression de texte écrite à l'aide d'une syntaxe C# en délégués (ou arbre d'expression).Les expressions sont analysées et transformées en Arbres d'expression sans recourir à la compilation ou à la réflexion.

Vous pouvez écrire quelque chose comme :

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

ou

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);

Mon travail est basé sur l'article de Scott Gu http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx .

Tout cela fonctionnerait certainement.Personnellement, pour ce problème particulier, j'adopterais probablement une approche légèrement 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 comme celui-ci, vous devez faire attention à 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 homologues de grande classe gonflés.

J'ai réalisé que ce n'était pas exactement la question, mais la question a reçu une assez bonne réponse et j'ai pensé qu'une approche alternative pourrait peut-être aider.

Je ne le sais pas maintenant si vous souhaitez absolument exécuter des instructions C#, mais vous pouvez déjà exécuter des instructions Javascript en C# 2.0.La bibliothèque open source Jint est capable de le faire.C'est un interpréteur Javascript pour .NET.Passez un programme Javascript et il s'exécutera dans votre application.Vous pouvez même transmettre un objet C# comme arguments et effectuer une automatisation dessus.

De plus, si vous souhaitez simplement évaluer l'expression de vos propriétés, essayez NCalc.

Vous pouvez utiliser la réflexion pour obtenir la propriété et l'invoquer.Quelque chose comme ça:

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

Autrement dit, en supposant que l'objet qui possède la propriété s'appelle "theObject" :)

Vous pouvez également implémenter un navigateur Web, puis charger un fichier HTML contenant du javascript.

Alors tu vas pour le document.InvokeScript Méthode sur ce navigateur.La valeur de retour de la fonction eval peut être récupérée et convertie en tout ce dont vous avez besoin.

Je l'ai fait dans plusieurs projets et cela fonctionne parfaitement.

J'espère que cela aide

Vous pourriez le faire avec une fonction prototype :

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

et ainsi de suite...

Utilise la réflexion pour analyser et évaluer une expression de liaison de données par rapport à un objet au moment de l'exécution.

Méthode DataBinder.Eval

J'ai écrit un paquet, SharpByte.Dynamic, pour simplifier la tâche de compilation et d'exécution du code de manière dynamique.Le code peut être invoqué sur n'importe quel objet contextuel à l'aide des méthodes d'extension comme détaillé plus loin. ici.

Par exemple,

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

renvoie 3 ;

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

renvoie la représentation sous forme de chaîne de l'objet contextuel ;

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

exécute ces instructions sous forme de script, etc.

Les exécutables peuvent être obtenus facilement en utilisant une méthode d'usine, comme le montre l'exemple ici--tout ce dont vous avez besoin est le code source et la liste de tous les paramètres nommés attendus (les jetons sont intégrés en utilisant une notation à trois crochets, telle que {{{0}}}, pour éviter les collisions avec string.Format() ainsi qu'avec guidon- comme les syntaxes) :

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

Chaque objet exécutable (script ou expression) est thread-safe, peut être stocké et réutilisé, prend en charge la journalisation à partir d'un script, stocke les informations de synchronisation et la dernière exception si elle est rencontrée, etc.Il existe également une méthode Copy() compilée sur chacun pour permettre de créer des copies bon marché, c'est-à-direutiliser un objet exécutable compilé à partir d'un script ou d'une expression comme modèle pour en créer d'autres.

La surcharge liée à l'exécution d'un script ou d'une instruction déjà compilé est relativement faible, bien inférieure à une microseconde sur un matériel modeste, et les scripts et expressions déjà compilés sont mis en cache pour être réutilisés.

J'essayais d'obtenir la valeur d'un membre de la structure (classe) par son nom.La structure n'était pas dynamique.Toutes les réponses n'ont pas fonctionné jusqu'à ce que je les obtienne enfin :

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

Cette méthode renverra la valeur du membre par son nom.Cela fonctionne sur une structure régulière (classe).

Vous pourriez vérifier le Héléonix.Réflexion bibliothèque.Il fournit des méthodes pour obtenir/définir/invoquer des membres de manière dynamique, y compris des membres imbriqués, ou si un membre est clairement défini, vous pouvez créer un getter/setter (lambda compilé dans un délégué) qui est plus rapide que la réflexion :

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

Ou si le nombre de propriétés n'est pas infini, vous pouvez générer des setters et les mettre en cache (les setters sont plus rapides puisqu'ils sont des délégués compilés) :

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

Les setters peuvent être du type Action<object, object> mais les instances peuvent être différentes au moment de l'exécution, vous pouvez donc créer des listes de setters.

Malheureusement, C# ne dispose pas de fonctionnalités natives pour faire exactement ce que vous demandez.

Cependant, mon programme d'évaluation C# permet d'évaluer le code C#.Il permet d'évaluer le code C# au moment de l'exécution et prend en charge de nombreuses instructions C#.En fait, ce code est utilisable dans n'importe quel projet .NET, cependant, il est limité à l'utilisation de la syntaxe C#.Jetez un œil à mon site Web, http://csharp-eval.com, pour plus de détails.

la bonne réponse est que vous devez mettre en cache tous les résultats pour maintenir une faible utilisation de la mémoire.

un exemple ressemblerait à ceci

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

et ajoutez-le à une liste

List<string> results = new List<string>();
for() results.Add(result);

enregistrez l'identifiant et utilisez-le dans le code

J'espère que cela t'aides

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top