Как я могу оценивать код С# динамически?

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

То, что я точно пытаюсь сделать, это то, что у меня есть целочисленная переменная (скажем i), и у меня есть несколько свойств по именам: "Property1", "Property2", "Property3" и т.д. Теперь я хочу выполнить некоторые операции над свойством Propertyi в зависимости от значения i.

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

Ответ 1

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

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

Этот пост на MSDN содержит ответ с некоторым примером кода на странице несколько:
создать анонимный метод из строки?

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

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


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

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

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

Ссылка: Свойство PropertyInfo.SetValue

Ответ 2

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

Ответ 3

Все это определенно сработает. Лично для этой конкретной проблемы я, вероятно, придерживаюсь немного другого подхода. Может быть, что-то вроде этого:

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

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

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

Ответ 4

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

}

Ответ 5

Я написал проект с открытым исходным кодом 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);

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

Ответ 6

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

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

Ответ 7

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

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

Ответ 8

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

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

То есть, если предположить, что объект, обладающий свойством, называется "Объект":)

Ответ 9

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

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

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

Надеюсь, что это поможет

Ответ 10

Вы можете сделать это с помощью прототипа функции:

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

и т.д.

Ответ 11

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

Метод DataBinder.Eval

Ответ 12

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

Например,

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

выполняет эти утверждения как script и т.д.

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

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

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

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

Ответ 13

К сожалению, у С# нет каких-либо родных средств для выполнения именно того, что вы просите.

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

Ответ 14

правильный ответ: вам нужно кэшировать весь результат, чтобы сохранить использование memory низким.

пример будет выглядеть следующим образом:

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

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

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