100

eval("something()");JavaScript でコードを動的に実行することができます。C# で同じことを行う方法はありますか?

私がやろうとしていることの例は次のとおりです: 私は整数変数 (たとえばi) を持っており、「Property1」、「Property2」、「Property3」などの名前で複数のプロパティがあります。の値に応じて、「Property ii 」プロパティで。

これは Javascript を使用すると非常に簡単です。C#でこれを行う方法はありますか?

4

16 に答える 16

49

免責事項:この回答は 2008 年に書かれたものです。それ以来、状況は劇的に変化しました。

このページの他の回答、特に詳しく説明している回答を見てくださいMicrosoft.CodeAnalysis.CSharp.Scripting

残りの回答は最初に投稿されたままになりますが、もはや正確ではありません。


残念ながら、C# はそのような動的言語ではありません。

ただし、できることは、クラスとすべてを含む C# ソース コード ファイルを作成し、C# の CodeDom プロバイダーを介して実行し、それをアセンブリにコンパイルしてから実行することです。

MSDN のこのフォーラム投稿には、ページの下にいくつかのサンプル コードを含む回答が含まれてい
ます。文字列から匿名メソッドを作成しますか?

これが非常に良い解決策だとは言いませんが、とにかく可能です。

その文字列にはどのようなコードが期待されますか? それが有効なコードのマイナー サブセット (たとえば数式のみ) である場合は、他の代替手段が存在する可能性があります。


編集:まあ、それは最初に質問を徹底的に読むことを教えてくれます. はい、ここでリフレクションが役立ちます。

文字列を ; で分割した場合 まず、個々のプロパティを取得するには、次のコードを使用してクラスの特定のプロパティの PropertyInfo オブジェクトを取得し、そのオブジェクトを使用して特定のオブジェクトを操作します。

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

リンク: PropertyInfo.SetValue メソッド

于 2008-08-07T12:31:18.530 に答える
14

あまり。リフレクションを使用して目的を達成することはできますが、Javascript ほど単純ではありません。たとえば、オブジェクトのプライベート フィールドを何かに設定したい場合は、次の関数を使用できます。

protected static void SetField(object o, string fieldName, object value)
{
   FieldInfo field = o.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);
   field.SetValue(o, value);
}
于 2008-08-07T12:31:07.563 に答える
12

これは、c# での評価関数です。これを使用して、匿名関数 (ラムダ式) を文字列から変換しました。ソース: 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;

}
于 2011-06-23T16:25:10.450 に答える
11

C#構文を使用して記述されたテキスト式をデリゲート(または式ツリー)に変換できるオープンソースプロジェクト、DynamicExpressoを作成しました。式は、コンパイルやリフレクションを使用せずに解析され、式ツリーに変換されます。

次のように書くことができます:

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

また

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

私の仕事は、ScottGuの記事http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspxに基づいています。

于 2013-02-03T09:29:02.080 に答える
7

それはすべて間違いなくうまくいくでしょう。個人的には、その特定の問題については、おそらく少し異なるアプローチを取るでしょう。多分このようなもの:

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

このようなパターンを使用する場合、データが値ではなく参照によって保存されるように注意する必要があります。つまり、プリミティブでこれを行わないでください。それらの大きく肥大化したクラスの対応物を使用する必要があります。

それは正確な質問ではないことに気付きましたが、質問にはかなりよく答えられており、別のアプローチが役立つかもしれないと思いました.

于 2008-08-07T12:47:19.887 に答える
5

絶対に C# ステートメントを実行したい場合は、今はしませんが、C# 2.0 では既に Javascript ステートメントを実行できます。オープンソース ライブラリのJintがそれを可能にします。.NET 用の Javascript インタープリターです。Javascript プログラムを渡すと、アプリケーション内で実行されます。C# オブジェクトを引数として渡して、自動化することもできます。

また、プロパティで式を評価したいだけの場合は、NCalcを試してください。

于 2009-10-14T08:06:54.007 に答える
4

リフレクションを使用してプロパティを取得し、呼び出すことができます。このようなもの:

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

つまり、プロパティを持つオブジェクトが「theObject」と呼ばれると仮定します:)

于 2008-08-07T12:29:50.530 に答える
1

リフレクションを使用して、実行時にオブジェクトに対するデータバインディング式を解析および評価します。

DataBinder.Evalメソッド

于 2011-11-05T14:40:26.940 に答える
1

また、Web ブラウザーを実装してから、javascript を含む html ファイルをロードすることもできます。

次にdocument.InvokeScript、このブラウザでメソッドを選択します。eval 関数の戻り値をキャッチして、必要なものすべてに変換できます。

私はいくつかのプロジェクトでこれを行いましたが、完全に機能します。

それが役に立てば幸い

于 2010-10-01T17:03:43.097 に答える
0

プロトタイプ関数でそれを行うことができます:

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

等々...

于 2008-08-07T12:30:59.763 に答える
-1

残念ながら、C# には、求めていることを正確に実行するためのネイティブ機能がありません。

ただし、私の C# eval プログラムでは、C# コードを評価できます。実行時に C# コードを評価できるようにし、多くの C# ステートメントをサポートします。実際、このコードは任意の .NET プロジェクト内で使用できますが、C# 構文の使用に制限されています。詳細については、私の Web サイトhttp://csharp-eval.comを参照してください。

于 2011-06-10T02:24:37.590 に答える
-9

正解は、mem0ryの使用量を低く抑えるために、すべての結果をキャッシュする必要があるということです。

例は次のようになります

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

それをリストに追加します

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

IDを保存し、コードで使用します

お役に立てれば

于 2011-08-26T12:37:30.587 に答える