Mogę zrobić eval("something()");
wykonać kod dynamicznie w JavaScript. Czy istnieje sposób, aby zrobić to samo w C #?
Przykładem tego, co próbuję zrobić, jest: Mam zmienną całkowitą (powiedzmy i
) i mam wiele właściwości o nazwach: „Właściwość1”, „Właściwość2”, „Właściwość3” itd. Teraz chcę wykonać kilka operacji na właściwości „Property i ” w zależności od wartości i
.
Z Javascriptem jest to naprawdę proste. Czy jest jakiś sposób, aby to zrobić za pomocą C #?
c#
reflection
properties
c#-2.0
Adhip Gupta
źródło
źródło
Odpowiedzi:
Niestety, C # nie jest takim dynamicznym językiem.
Możesz jednak utworzyć plik kodu źródłowego w języku C #, pełen klas i wszystkim, i uruchomić go za pośrednictwem dostawcy CodeDom dla C # i skompilować go w zestawie, a następnie wykonać.
Ten post na forum w witrynie MSDN zawiera odpowiedź z przykładowym kodem nieco poniżej strony:
utworzyć anonimową metodę na podstawie ciągu znaków?
Trudno powiedzieć, że jest to bardzo dobre rozwiązanie, ale i tak jest możliwe.
Jakiego rodzaju kodu będziesz się spodziewać w tym ciągu? Jeśli jest to niewielki podzbiór prawidłowego kodu, na przykład tylko wyrażenia matematyczne, może to oznaczać, że istnieją inne alternatywy.
Edycja : Cóż, to uczy mnie najpierw dokładnie przeczytać pytania. Tak, refleksja może ci tu pomóc.
Jeśli podzielisz ciąg przez; po pierwsze, aby uzyskać indywidualne właściwości, możesz użyć następującego kodu w celu pobrania obiektu PropertyInfo dla określonej właściwości dla klasy, a następnie użyć tego obiektu do manipulowania określonym obiektem.
String propName = "Text"; PropertyInfo pi = someObject.GetType().GetProperty(propName); pi.SetValue(someObject, "New Value", new Object[0]);
Link: Metoda PropertyInfo.SetValue
źródło
GetMethod(methodName)
zamiast tego przeanalizować wartości parametrów i wywołać metodę przy użyciu odbicia.Korzystanie z interfejsu API skryptów Roslyn (więcej przykładów tutaj ):
// add NuGet package 'Microsoft.CodeAnalysis.Scripting' using Microsoft.CodeAnalysis.CSharp.Scripting; await CSharpScript.EvaluateAsync("System.Math.Pow(2, 4)") // returns 16
Możesz także uruchomić dowolny fragment kodu:
var script = await CSharpScript.RunAsync(@" class MyClass { public void Print() => System.Console.WriteLine(1); }")
I odwołaj się do kodu, który został wygenerowany w poprzednich uruchomieniach:
await script.ContinueWithAsync("new MyClass().Print();");
źródło
Nie całkiem. Możesz użyć refleksji, aby osiągnąć to, co chcesz, ale nie będzie to tak proste, jak w Javascript. Na przykład, jeśli chcesz ustawić na coś pole prywatne obiektu, możesz użyć tej funkcji:
protected static void SetField(object o, string fieldName, object value) { FieldInfo field = o.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic); field.SetValue(o, value); }
źródło
To jest funkcja eval w języku C #. Użyłem go do konwersji funkcji anonimowych (wyrażeń lambda) z łańcucha. Źródło: 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; }
źródło
Napisałem projekt typu open source, Dynamic Expresso , który może konwertować wyrażenia tekstowe napisane przy użyciu składni C # na delegatów (lub drzewo wyrażeń). Wyrażenia są analizowane i przekształcane w drzewa wyrażeń bez użycia kompilacji lub odbicia.
Możesz napisać coś takiego:
var interpreter = new Interpreter(); var result = interpreter.Eval("8 / 2 + 2");
lub
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);
Moja praca opiera się na artykule Scotta Gu http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx .
źródło
Wszystko to na pewno by się udało. Osobiście w przypadku tego konkretnego problemu prawdopodobnie podjąłbym nieco inne podejście. Może coś takiego:
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 } }
Korzystając z takich wzorców, musisz uważać, aby Twoje dane były przechowywane przez odniesienie, a nie według wartości. Innymi słowy, nie rób tego z prymitywami. Musisz użyć ich wielkich, nadętych klasowych odpowiedników.
Zdałem sobie sprawę, że to nie jest dokładnie to pytanie, ale odpowiedź na nie jest całkiem dobra i pomyślałem, że może pomoże alternatywne podejście.
źródło
Nie robię tego teraz, jeśli absolutnie chcesz wykonywać instrukcje C #, ale możesz już wykonywać instrukcje Javascript w C # 2.0. Biblioteka open source Jint jest w stanie to zrobić. Jest to interpreter JavaScript dla .NET. Przekaż program Javascript, a będzie on działał w Twojej aplikacji. Możesz nawet przekazać obiekt C # jako argumenty i wykonać na nim automatyzację.
Jeśli chcesz po prostu oszacować wyrażenie na swoich właściwościach, wypróbuj NCalc .
źródło
Możesz użyć odbicia, aby pobrać właściwość i wywołać ją. Coś takiego:
object result = theObject.GetType().GetProperty("Property" + i).GetValue(theObject, null);
Oznacza to, że zakładając, że obiekt, który ma tę właściwość, nosi nazwę „theObject” :)
źródło
Możesz także zaimplementować przeglądarkę internetową, a następnie załadować plik html, który zawiera JavaScript.
Następnie przejdź do
document.InvokeScript
metody w tej przeglądarce. Wartość zwracaną przez funkcję eval można przechwycić i przekonwertować na wszystko, czego potrzebujesz.Zrobiłem to w kilku projektach i działa idealnie.
Mam nadzieję, że to pomoże
źródło
Możesz to zrobić za pomocą funkcji prototypu:
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); }
i tak dalej...
źródło
Używa odbicia do analizowania i oceniania wyrażenia powiązania danych względem obiektu w czasie wykonywania.
Metoda DataBinder.Eval
źródło
Napisałem pakiet SharpByte.Dynamic , aby uprościć zadanie kompilowania i dynamicznego wykonywania kodu. Kod można wywołać na dowolnym obiekcie kontekstu przy użyciu metod rozszerzających, jak opisano szczegółowo tutaj .
Na przykład,
someObject.Evaluate<int>("6 / {{{0}}}", 3))
zwraca 3;
someObject.Evaluate("this.ToString()"))
zwraca reprezentację ciągu obiektu kontekstu;
someObject.Execute(@ "Console.WriteLine(""Hello, world!""); Console.WriteLine(""This demonstrates running a simple script""); ");
uruchamia te instrukcje jako skrypt itp.
Pliki wykonywalne można łatwo uzyskać za pomocą metody fabrycznej, jak pokazano na poniższym przykładzie - wszystko , czego potrzebujesz, to kod źródłowy i lista wszelkich oczekiwanych nazwanych parametrów (tokeny są osadzane przy użyciu notacji z potrójnym nawiasem, np. {{{0}} }, aby uniknąć kolizji z string.Format (), a także składniami podobnymi do Handlebars):
Każdy obiekt wykonywalny (skrypt lub wyrażenie) jest bezpieczny dla wątków, może być przechowywany i ponownie używany, obsługuje logowanie z poziomu skryptu, przechowuje informacje o czasie i ostatnim wyjątku, jeśli zostanie napotkany itp. Istnieje również skompilowana metoda Copy (), która umożliwia tworzenie tanich kopii, czyli używanie obiektu wykonywalnego skompilowanego ze skryptu lub wyrażenia jako szablonu do tworzenia innych.
Narzut związany z wykonaniem już skompilowanego skryptu lub instrukcji jest stosunkowo niski, znacznie poniżej mikrosekundy na skromnym sprzęcie, a już skompilowane skrypty i wyrażenia są buforowane do ponownego wykorzystania.
źródło
Próbowałem uzyskać wartość elementu struktury (klasy) według jego nazwy. Struktura nie była dynamiczna. Wszystkie odpowiedzi nie działały, dopóki w końcu ich nie otrzymałem:
public static object GetPropertyValue(object instance, string memberName) { return instance.GetType().GetField(memberName).GetValue(instance); }
Ta metoda zwróci wartość elementu członkowskiego według jego nazwy. Działa na regularnej strukturze (klasie).
źródło
Możesz sprawdzić bibliotekę Heleonix.Reflection . Zapewnia metody dynamicznego pobierania / ustawiania / wywoływania elementów członkowskich, w tym zagnieżdżonych elementów członkowskich, lub jeśli element członkowski jest jasno zdefiniowany, można utworzyć metodę pobierającą / ustawiającą (lambda skompilowaną do delegata), która jest szybsza niż odbicie:
var success = Reflector.Set(instance, null, $"Property{i}", value);
Lub jeśli liczba właściwości nie jest nieskończona, możesz wygenerować setery i zmienić je (setery są szybsze, ponieważ są skompilowanymi delegatami):
var setter = Reflector.CreateSetter<object, object>($"Property{i}", typeof(type which contains "Property"+i)); setter(instance, value);
Setery mogą być typu,
Action<object, object>
ale instancje mogą być różne w czasie wykonywania, więc możesz tworzyć listy seterów.źródło
Niestety, C # nie ma żadnych natywnych możliwości robienia dokładnie tego, o co prosisz.
Jednak mój program C # eval pozwala na ocenę kodu C #. Zapewnia ocenę kodu C # w czasie wykonywania i obsługuje wiele instrukcji C #. W rzeczywistości ten kod jest używany w każdym projekcie .NET, jednak jest on ograniczony do używania składni C #. Zajrzyj na moją stronę internetową http://csharp-eval.com , aby uzyskać dodatkowe informacje.
źródło
Prawidłowa odpowiedź brzmi: musisz buforować wszystkie wyniki, aby utrzymać niskie zużycie pamięci.
przykład wyglądałby tak
TypeOf(Evaluate) { "1+1":2; "1+2":3; "1+3":5; .... "2-5":-3; "0+0":1 }
i dodaj go do listy
List<string> results = new List<string>(); for() results.Add(result);
zapisz identyfikator i użyj go w kodzie
mam nadzieję że to pomoże
źródło