어떻게 평가할 수 있 C#코드를 동적으로?
-
08-06-2019 - |
문제
내가 할 수 있습니다 eval("something()");
코드를 실행하려면 동적으로 자바 스크립트에서.방법은 없을 경우 이와 같은 작업을 수행 C#?
예를 들어 내가 무엇을 하려고 하:나는 변수의 정수(말 i
다)및 여러 특성에 의해 이름:"Property1","Property2","Property3",등등.지금,나는 몇 가지 작업을 수행에"속성나 "속성 값에 따라 i
.
이것은 정말 간단합니다.어떤 방법으로 C#?
해결책
불행하게도,C#지 않는 동적 언어와 같습니다.
무엇을 할 수 있는,그러나,을 만드는 C#소스 코드 파일의 전체 클래스고 모든 것,그리고 그것을 실행을 통해 CodeDom 공급자를 위한 C#컴파일을 어셈블리로,다음을 실행합니다.
이 포럼에 게시 MSDN 포함되어 있는 대답으로 몇 가지 예제 코드는 아래 페이지를 다소:
을 만들 익명의 방법은 문자열에서?
내가 이 말을 거의 매우 좋은 해결책이지만,그건 어쨌든이 가능합니다.
어떤 종류의 코드가 기대에는 문자열?는 경우에 그것은 미성년자 하위 집합의 올바른 코드,예를 들어 단지 수학적인 표현할 수 있습는 다른 대안이 존재합니다.
편집:잘 가르치는 나에게 질문을 읽을 철저하게 처음이다.Yes,반영할 수 있을 것입을 줄 당신은 어떤 도움이 여기에.
당신이 문자열을 분할하여;첫째로,개인 속성을 사용할 수 있습니다,다음 코드를 얻을 PropertyInfo 객체를 특정 속성 클래스에 대해,다음 사용하는 개체를 조작하는 특정 개체입니다.
String propName = "Text";
PropertyInfo pi = someObject.GetType().GetProperty(propName);
pi.SetValue(someObject, "New Value", new Object[0]);
다른 팁
를 사용하는 로슬린 스크립트 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();");
하지 않습니다.할 수 있는 리플렉션을 사용하여 달성하기 위해 무엇을 원하지만,그것은 없을 거에서와 같이 간단합니다.는 경우 예를 들어,설정하고 싶어 프라이빗 필드는 개체의 무언가에 사용할 수 있습니다 이 기능:
protected static void SetField(object o, string fieldName, object value)
{
FieldInfo field = o.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);
field.SetValue(o, value);
}
이는 평가에 따라 기능을 수 있습니다.나는 그것을 사용하는 익명으로 변환 기능을(람다 식)문자열.출처: 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#구문으로 명(또는 식 트리).식 분석 및으로 변형 식 트 없이 사용하여 컴파일하거나 반영합니다.
를 작성할 수 있습 같은 것:
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);
내 작업에 기반한 스콧 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
}
}
을 사용할 때와 같은 패턴이,당신은 조심해야는 데이터가 저장된 참조로 아닌 값입니다.다시 말해서,이것을 하지 않는 프리미티브와 함께.당신을 사용하여 그들의 큰 부풀어준다.
내가 깨달았는지 정확하게 질문,하지만 질문되었습 꽤 잘 대답하고 나는 생각 어쩌면 다른 방법은 도움이 될 수 있습니다.
당신이 사용할 수 있는 리플렉션을 제공하고 호출니다.무언가 이것을 좋아한다:
object result = theObject.GetType().GetProperty("Property" + i).GetValue(theObject, null);
는 경우가 있는 객체의 속성이라고"개체":)
당신은 또한 당신을 구현할 수있는 컨트롤,다음을 로드하는 html 파일을 포함합니다.
다음 u 에 대한 이동 document.InvokeScript
방법 이 브라우저입니다.의 반환 값 eval 기능을 사로 변환 모든 것을 당신이 필요합니다.
내가 이것에서 여러 프로젝트에 완벽하게 작동합니다.
그것을 희망하는 데 도움이
당신은 그것을 할 수 있으로 시제품 기능:
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);
}
그래서...
리플렉션을 사용하여 구문 분석하고 평가할 데이터 바인딩 표현에 대한 개체를 수행할 필요는 없습니다.
작성,패키지 SharpByte.동, 를 단순화하는 작업을 컴파일하고 실행하는 코드를 동적으로.코드가 호출될 수 있는 모든 컨텍스트를 사용하여 개체 연장 방법으로 상세한 기.
예를 들어,
someObject.Evaluate<int>("6 / {{{0}}}", 3))
3 을 반환합니다;
someObject.Evaluate("this.ToString()"))
컨텍스트를 반환하는 개체의 문자열 표현은;
someObject.Execute(@
"Console.WriteLine(""Hello, world!"");
Console.WriteLine(""This demonstrates running a simple script"");
");
실행 그 문을 스크립트로,등등.
실행 파일을 얻을 수 있을 사용하여 쉽게 공장 방법에서 볼 수 있듯이,예 기-모든 필요한 소스 코드고 목록의 예상 매개 변수 이름의(토큰은 임베디드를 사용하여 트리플-브라켓 표기법과 같은{{{0}}},으로 충돌을 방지하는 문자열입니다.형식()뿐만 아니라 자전거 핸들과 같은 구문):
IExecutable executable = ExecutableFactory.Default.GetExecutable(executableType, sourceCode, parameterNames, addedNamespaces);
각 실행 가능한 개체(스크립트 또는 식)은 스레드에 안전,저장 및 재사용,로그할 수 있도록 지원합니다.에서 스크립트에서는 타이밍 정보를 저장하고 마지막에 예외가 발생한 경우,등등.또한 복사본()메소드를 컴파일에 각을 만들 수 있도록 저렴한 복사본을 즉를 사용하여 실행 가능한 개체를 컴파일 스크립트에서 또는 식으로 템플릿을 만들기 위한 다른 사람입니다.
오버헤드를 실행하는 이미 컴파일 스크립트나 문은 상대적으로 낮에만에서 마이크로초에 겸손한 하드웨어 및 이미 컴파일 스크립트와 표현에 대해 캐시되 재사용할 수 있습니다.
그러려고의 가치는 구조물(클래스)구성원에 의해 그것의 이름입니다.구조되지 않았다.모든 답 작동하지 않을 때까지 마지막으로 그것을 얻:
public static object GetPropertyValue(object instance, string memberName)
{
return instance.GetType().GetField(memberName).GetValue(instance);
}
이 방법은 값을 반환합의 구성원에 의해 그것의 이름입니다.그것은 작품에서는 정기적인 구조(클래스).
확인할 수 있습니다 Heleonix.반사 라이브러리입니다.그것은 방법을 제공합니다 get/set/invoke 멤버를 동적으로 포함한 중첩된 회원은 경우,또는 회원이 명확하게 정의를 만들 수 있습 get/set(람다로 컴파일을 위임)어떤 이상 빠른 반사:
var success = Reflector.Set(instance, null, $"Property{i}", value);
는 경우 또는 속성의 수는지 끝이없는,당신을 생성할 수 있는 세터 및 chache 들(setters 빠르기 때문 컴파일되는 대리인):
var setter = Reflector.CreateSetter<object, object>($"Property{i}", typeof(type which contains "Property"+i));
setter(instance, value);
Setters 수 있습의 유형 Action<object, object>
그러나 인스턴스와 다를 수 있습니다 runtime,그래서 당신의 목록을 만들 수 있습 setter.
불행하게도,C#없는 기본 시설을 정확히 무엇을 요청하고 있습니다.
그러나 내 C#평가 프로그램으로 허용하지 않을 평가하는 C#코드입니다.제공해 평가하는 C#에 코드를 런타임이 지원하고 많은 C#문입니다.사실,이 코드를 사용할 수 있습니다.NET 프로젝트,그러나,그것은 제한을 사용하여 C#문입니다.에서 봐야,웹사이트 http://csharp-eval.com, 추가 정보.
올바른 응답이 필요 캐시 모든 결과를 유지하 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);
save id 에서 사용하는 코드
이