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

голоса
75

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

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

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

Задан 07/08/2008 в 13:26
источник пользователем
На других языках...                            


16 ответов

голоса
41

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

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

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

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

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


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

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

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

Ссылка: PropertyInfo.SetValue метод

Ответил 07/08/2008 в 13:31
источник пользователем

голоса
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);
}
Ответил 07/08/2008 в 13:31
источник пользователем

голоса
10

Использование Рослин сценариев 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();");
Ответил 23/06/2016 в 06:33
источник пользователем

голоса
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 .

Ответил 03/02/2013 в 10:29
источник пользователем

голоса
7

Это Eval функция под 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;

}
Ответил 23/06/2011 в 17:25
источник пользователем

голоса
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
  }
}

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

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

Ответил 07/08/2008 в 13:47
источник пользователем

голоса
5

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

Кроме того, если вы просто хотите , чтобы оценить выражение ваших свойств, дать попробовать на NCalc .

Ответил 14/10/2009 в 09:06
источник пользователем

голоса
3

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

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

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

Ответил 07/08/2008 в 13:29
источник пользователем

голоса
1

Вы также могли бы реализовать WebBrowser, а затем загружают HTML-файл, которым содержит JavaScript.

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

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

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

Ответил 01/10/2010 в 18:03
источник пользователем

голоса
0

Вы можете проверить Heleonix.Reflection библиотеку. Он предоставляет методы для получения / набор / вызова пользователей динамически, в том числе вложенных членов, или если член четко определено, вы можете создать геттер / сеттер (лямбда компилируется в качестве делегата) , который быстрее , чем отражение:

var success = Reflector.Set(instance, null, $"Property{i}", value);

Или, если число свойств не является бесконечным, вы можете генерировать сеттеры и chache их (сеттеры быстрее, так как они скомпилированы делегатов):

var setter = Reflector.CreateSetter<object, object>($"Property{i}", typeof(type which contains "Property"+i));
setter(instance, value);

Инкубационные может быть типа , Action<object, object>но случаи могут быть разными во время выполнения, так что вы можете создавать списки сеттеров.

Ответил 13/07/2018 в 10:04
источник пользователем

голоса
0

Я пытаюсь получить значение элемента (класса) структур по его имени. Структура не была динамичной. Все ответы не работал, пока я, наконец, получил его:

public static object GetPropertyValue(object instance, string memberName)
{
    return instance.GetType().GetField(memberName).GetValue(instance);
}

Этот метод возвращает значение элемента по его имени. Он работает на регулярной структуры (класс).

Ответил 02/05/2018 в 13:56
источник пользователем

голоса
0

Я написал пакет, 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"");
");

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

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

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

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

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

Ответил 14/08/2017 в 11:28
источник пользователем

голоса
0

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

Метод DataBinder.Eval

Ответил 05/11/2011 в 15:40
источник пользователем

голоса
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);
}

и так далее...

Ответил 07/08/2008 в 13:30
источник пользователем

голоса
-1

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

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

Ответил 10/06/2011 в 03:24
источник пользователем

голоса
-8

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

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

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

Ответил 26/08/2011 в 13:37
источник пользователем

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more