Я могу eval("something()");
выполнить код динамически в JavaScript. Есть ли у меня способ сделать то же самое на C #?
Пример того, что я пытаюсь сделать: у меня есть целочисленная переменная (скажем i
), и у меня есть несколько свойств по именам: «Свойство1», «Свойство2», «Свойство3» и т. Д. Теперь я хочу выполнить некоторые операции по свойству "Свойство i " в зависимости от значения i
.
С Javascript это действительно просто. Есть ли способ сделать это с помощью C #?
c#
reflection
properties
c#-2.0
Адип Гупта
источник
источник
Ответы:
К сожалению, C # не является таким динамическим языком.
Однако вы можете создать файл исходного кода C #, полный классов и всего остального, запустить его через провайдер CodeDom для C # и скомпилировать его в сборку, а затем выполнить.
Это сообщение на форуме MSDN содержит ответ с некоторым примером кода ниже по странице:
создать анонимный метод из строки?
Я бы не сказал, что это очень хорошее решение, но все же возможно.
Какой код вы ожидаете в этой строке? Если это незначительное подмножество действительного кода, например, просто математические выражения, возможно, существуют другие альтернативы.
Изменить : Ну, это учит меня сначала внимательно читать вопросы. Да, здесь рефлексия может вам помочь.
Если вы разделите строку на; Во-первых, чтобы получить отдельные свойства, вы можете использовать следующий код, чтобы получить объект PropertyInfo для определенного свойства для класса, а затем использовать этот объект для управления определенным объектом.
String propName = "Text"; PropertyInfo pi = someObject.GetType().GetProperty(propName); pi.SetValue(someObject, "New Value", new Object[0]);
Ссылка: Метод PropertyInfo.SetValue
источник
GetMethod(methodName)
вместо этого, проанализировать значения параметров и вызвать метод с помощью отражения.Использование скриптового 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();");
источник
На самом деле, нет. Вы можете использовать отражение для достижения желаемого, но это будет не так просто, как в 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); }
источник
Это функция 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; }
источник
Я написал проект с открытым исходным кодом Dynamic Expresso , который может преобразовывать текстовые выражения, написанные с использованием синтаксиса 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);
Моя работа основана на статье Скотта Гу 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 #, но вы уже можете выполнять операторы Javascript в C # 2.0. Библиотека с открытым исходным кодом Jint может это сделать. Это интерпретатор Javascript для .NET. Передайте программу Javascript, и она будет работать внутри вашего приложения. Вы даже можете передать объект C # в качестве аргументов и автоматизировать его.
Также, если вы просто хотите оценить выражение своих свойств, попробуйте NCalc .
источник
Вы можете использовать отражение, чтобы получить свойство и вызвать его. Что-то вроде этого:
object result = theObject.GetType().GetProperty("Property" + i).GetValue(theObject, null);
То есть, предполагая, что объект, обладающий этим свойством, называется «theObject» :)
источник
Вы также можете реализовать веб-браузер, а затем загрузить html-файл, содержащий javascript.
Затем перейдите к
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); }
и так далее...
источник
Использует отражение для анализа и оценки выражения привязки данных к объекту во время выполнения.
DataBinder.Eval Метод
источник
Я написал пакет 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""); ");
запускает эти операторы как сценарий и т. д.
Исполняемые файлы можно легко получить с помощью фабричного метода, как показано в примере здесь - все, что вам нужно, это исходный код и список любых ожидаемых именованных параметров (токены встроены с использованием записи с тройными скобками, например {{{0}} }, чтобы избежать конфликтов с string.Format (), а также синтаксисом, подобным Handlebars):
Каждый исполняемый объект (сценарий или выражение) является потокобезопасным, может быть сохранен и повторно использован, поддерживает ведение журнала из сценария, хранит информацию о времени и последнем исключении, если оно обнаружено, и т. Д. Также существует метод Copy (), скомпилированный для каждого, чтобы разрешить создание дешевых копий, т.е. использование исполняемого объекта, скомпилированного из сценария или выражения, в качестве шаблона для создания других.
Накладные расходы на выполнение уже скомпилированного сценария или оператора относительно невелики, менее микросекунды на скромном оборудовании, а уже скомпилированные сценарии и выражения кэшируются для повторного использования.
источник
Я пытался получить значение члена структуры (класса) по его имени. Структура не была динамичной. Все ответы не работали, пока я наконец не получил их:
public static object GetPropertyValue(object instance, string memberName) { return instance.GetType().GetField(memberName).GetValue(instance); }
Этот метод вернет значение члена по его имени. Работает по штатной структуре (классу).
источник
Вы можете проверить библиотеку Heleonix.Reflection . Он предоставляет методы для динамического получения / установки / вызова членов, включая вложенные члены, или, если член четко определен, вы можете создать метод получения / установки (лямбда, скомпилированный в делегат), который работает быстрее, чем отражение:
var success = Reflector.Set(instance, null, $"Property{i}", value);
Или, если количество свойств не бесконечно, вы можете сгенерировать сеттеры и привязать их (сеттеры быстрее, поскольку они являются скомпилированными делегатами):
var setter = Reflector.CreateSetter<object, object>($"Property{i}", typeof(type which contains "Property"+i)); setter(instance, value);
Сеттеры могут быть типа,
Action<object, object>
но экземпляры могут быть разными во время выполнения, поэтому вы можете создавать списки сеттеров.источник
К сожалению, в C # нет встроенных средств для выполнения именно того, о чем вы просите.
Однако моя программа eval на 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);
сохраните идентификатор и используйте его в коде
надеюсь это поможет
источник