2008-08-07 10 views
73

Я могу сделать eval("something()"); для динамического выполнения кода в JavaScript. Есть ли способ для меня сделать то же самое в C#?Как я могу оценить код C# динамически?

Что я точно пытаюсь сделать то, что у меня есть целочисленные переменный (скажет i) и у меня есть несколько свойств по именам: «property1», «свойство2», «Property3» и т.д. Теперь я хочу для выполнения некоторых операций над свойством «Свойство i» в зависимости от значения i.

Это очень просто с Javascript. Есть ли способ сделать это с помощью C#?

+2

C# call ironpython's eval. Я попробовал это в C# 4.0. нет опыта работы с C# 2.0 – 2011-05-15 03:00:56

+0

@Peter Long, где можно найти документацию по eval IronPython? – smartcaveman 2011-06-16 16:09:41

+0

Взгляните на [Mono CSharp interactive shell] (http://www.mono-project.com/CsharpRepl). Он имеет [eval-подобные функции] (http://www.go-mono.com/docs/index.aspx?link=N:Mono.CSharp). – 2011-02-27 20:28:24

ответ

40

К сожалению, C# не динамический язык, как это.

Однако вы можете создать файл исходного кода C#, полный класса и всего, и запустить его через поставщика CodeDom для C# и скомпилировать его в сборку, а затем выполнить.

Этот форум пост на MSDN содержит ответ с некоторыми примерами кода вниз страницы несколько:
create a anonymous method from a string?

я вряд ли бы сказать, что это очень хорошее решение, но это возможно в любом случае.

Какой код вы собираетесь ожидать в этой строке? Если это небольшое подмножество допустимого кода, например, только математические выражения, возможно, существуют другие альтернативы.


Редактировать: Ну, что учит меня читать вопросы тщательно первым. Да, размышления могли бы помочь вам здесь.

Если вы разделили строку на; во-первых, чтобы получить индивидуальные свойства, вы можете использовать следующий код, чтобы получить объект PropertyInfo для определенного свойства для класса, а затем использовать этот объект для управления определенным объектом.

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

Ссылка: PropertyInfo.SetValue Method

2

Вы можете использовать отражение, чтобы получить свойство и вызвать его. Что-то вроде этого:

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

То есть, если предположить, что объект имеет свойство называется «theObject» :)

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

и так на ...

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

При использовании модели, как это, вы должны быть осторожны, что ваши данные хранятся в виде ссылки, а не по значению. Другими словами, не делайте этого с примитивами. Вы должны использовать своих больших раздутых коллег.

Я понял, что это не совсем вопрос, но вопрос был довольно хорошо ответил, и я подумал, что альтернативный подход может помочь.

5

Я не сейчас, если вы абсолютно хотите выполнять инструкции C#, но вы уже можете выполнять Javascript-инструкции в C# 2.0. Библиотека Jint с открытым исходным кодом способна это сделать. Это интерпретатор Javascript для .NET. Передайте Javascript программу, и она будет работать внутри вашего приложения. Вы даже можете передать объект C# в качестве аргументов и сделать автоматизацию на нем.

Также, если вы просто хотите оценить выражение в своих свойствах, попробуйте NCalc.

1

Вы также можете реализовать Webbrowser, а затем загрузить html-файл с javascript.

Тогда идите за document.InvokeScript Метод в этом браузере. Возвращаемое значение функции eval может быть выловлено и преобразовано во все, что вам нужно.

Я сделал это в нескольких проектах, и он отлично работает.

Надеется, что это помогает

-1

К сожалению, C# не имеет встроенные средств для делать именно то, что вы просите.

Однако моя программа C# eval позволяет оценивать код C#. Он обеспечивает оценку кода C# во время выполнения и поддерживает множество операторов C#. Фактически, этот код можно использовать в любом .NET-проекте, однако он ограничен синтаксисом C#. Посмотрите мой сайт, http://csharp-eval.com, для получения дополнительной информации.

+0

Посмотрите на [API-интерфейс Scripting API] (https://github.com/dotnet/roslyn/wiki/Scripting-API-Samples) – 2017-10-22 16:23:42

7

Это функция eval под C#. Я использовал его для преобразования анонимных функций (Lambda Expressions) из строки. Источник: 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; 

} 
+0

@sehe Упс, я исправил опечатку (Lambada => Lambda). Я не знал, что эта песня называется Ламбада, поэтому она была непреднамеренной. ;) – Largo 2011-12-23 22:47:03

-7

правильный ответ вам нужно кэшировать результат, чтобы сохранить низкий уровень использования 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); 

сохранить идентификатор и использовать его в коде

надеюсь, что это помогает

0

Использует отражение для анализа и оценки выражения привязки данных к объекту во время выполнения.

DataBinder.Eval Method

7

Я написал проект с открытым исходным кодом, Dynamic Expresso, который может преобразовывать текст, написанное с использованием выражения в C# синтаксиса в делегат (или дерево выражений).Выражения анализируются и преобразуются в Expression Trees без использования компиляции или отражения.

Вы можете написать что-то вроде:

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

Моя работа основана на статье Скотт Гу http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx.

6

Использование сценариев API Roslyn (более samples here):

// 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();"); 
0

Я написал пакет, SharpByte.Dynamic, чтобы упростить задачу o f компиляция и выполнение кода динамически. Код может быть вызван для любого объекта контекста с использованием методов расширения, как подробно описано ниже here.

Например,

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

запускает эти заявления как сценарий и т.д.

Исполняемые может быть получен легко, используя фабричный метод, как показано в примере here --all вам нужно исходный код и список любых ожидаемых названные параметры (маркеры встроены с помощью тройного кронштейна обозначения, таких как {{{0}}}, чтобы избежать столкновений с string.Format(), а также Рулями-подобные синтаксисы):

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

каждого исполняемым объектом (сценарий или выражение) является потокобезопасным, может быть хранилище d и повторно используется, поддерживает ведение журнала из сценария, хранит информацию о времени и последнее исключение, если они встречаются, и т. д. Также существует метод Copy(), который позволяет создавать дешевые копии, т. е. использовать исполняемый объект, скомпилированный из сценария или выражения как шаблон для создания других.

Накладные расходы на выполнение уже скомпилированного скрипта или оператора относительно низки, в то время как под микросекундой на скромном оборудовании, а уже скомпилированные скрипты и выражения кэшируются для повторного использования.