[c#] C # 코드를 동적으로 평가하려면 어떻게해야합니까?

eval("something()");JavaScript에서 코드를 동적으로 실행할 수 있습니다 . C #에서 동일한 작업을 수행 할 수있는 방법이 있습니까?

내가하려는 작업의 예는 다음과 같습니다. 정수 변수 (예 i:)가 있고 “Property1”, “Property2”, “Property3″등의 이름으로 여러 속성이 있습니다. 이제 몇 가지 작업을 수행하고 싶습니다. 의 값에 따라 “속성 i “속성에 i.

이것은 Javascript로 정말 간단합니다. C #으로이 작업을 수행 할 수있는 방법이 있습니까?



답변

불행히도 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 메서드


답변

Roslyn 스크립팅 API 사용 ( 여기에 더 많은 샘플 참조 ) :

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

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

모든 코드를 실행할 수도 있습니다.

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

그리고 이전 실행에서 생성 된 코드를 참조하십시오.

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


답변

별로. 리플렉션을 사용하여 원하는 것을 얻을 수 있지만 Javascript만큼 간단하지는 않습니다. 예를 들어 객체의 private 필드를 무언가로 설정하려면 다음 함수를 사용할 수 있습니다.

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


답변

이것은 c #의 평가 함수입니다. 문자열에서 익명 함수 (Lambda 표현식)를 변환하는 데 사용했습니다. 출처 : 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;

}


답변

C # 구문을 사용하여 작성된 텍스트 식을 대리자 (또는 식 트리)로 변환 할 수 있는 오픈 소스 프로젝트 Dynamic Expresso를 작성했습니다. 표현식은 컴파일이나 리플렉션을 사용하지 않고 구문 분석되고 표현식 트리 로 변환됩니다 .

다음과 같이 작성할 수 있습니다.

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

내 작업은 Scott Gu 기사 http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx를 기반으로 합니다.


답변

그 모든 것이 확실히 작동 할 것입니다. 개인적으로 그 특정 문제에 대해서는 아마도 조금 다른 접근 방식을 취할 것입니다. 아마도 다음과 같습니다.

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

이와 같은 패턴을 사용할 때 데이터가 값이 아닌 참조로 저장된다는 점에주의해야합니다. 즉, 프리미티브로이 작업을 수행하지 마십시오. 당신은 그들의 큰 부풀린 클래스 대응 물을 사용해야합니다.

나는 그것이 정확히 질문이 아니라는 것을 깨달았지만 그 질문에 대한 대답은 꽤 잘되어 있었고 대안적인 접근법이 도움이 될 것이라고 생각했습니다.


답변

C # 문을 절대적으로 실행하려면 지금은 아니지만 C # 2.0에서 이미 Javascript 문을 실행할 수 있습니다. 오픈 소스 라이브러리 Jint 가 할 수 있습니다. .NET 용 자바 스크립트 인터프리터입니다. 자바 스크립트 프로그램을 전달하면 애플리케이션 내에서 실행됩니다. C # 개체를 인수로 전달하고 자동화 할 수도 있습니다.

또한 속성에 대한 표현식을 평가하려는 경우 NCalc를 시도 하십시오 .