Saya bisa melakukan eval("something()");
untuk mengeksekusi kode secara dinamis di JavaScript. Apakah ada cara bagi saya untuk melakukan hal yang sama di C #?
Contoh dari apa yang saya coba lakukan adalah: Saya memiliki variabel integer (katakanlah i
) dan saya memiliki beberapa properti dengan nama: "Property1", "Property2", "Property3", dll. Sekarang, saya ingin melakukan beberapa operasi pada properti "Properti i " tergantung pada nilai i
.
Ini sangat sederhana dengan Javascript. Apakah ada cara untuk melakukan ini dengan C #?
c#
reflection
properties
c#-2.0
Adhip Gupta
sumber
sumber
Jawaban:
Sayangnya, C # bukanlah bahasa dinamis seperti itu.
Apa yang dapat Anda lakukan, bagaimanapun, adalah membuat file kode sumber C #, penuh dengan kelas dan semuanya, dan menjalankannya melalui penyedia CodeDom untuk C # dan mengkompilasinya menjadi sebuah rakitan, dan kemudian mengeksekusinya.
Posting forum di MSDN ini berisi jawaban dengan beberapa contoh kode di bawah halaman:
buat metode anonim dari string?
Saya tidak akan mengatakan ini adalah solusi yang sangat baik, tetapi tetap mungkin.
Jenis kode apa yang akan Anda harapkan dalam string itu? Jika itu adalah bagian kecil dari kode yang valid, misalnya hanya ekspresi matematika, mungkin ada alternatif lain.
Sunting : Nah, itu mengajari saya untuk membaca pertanyaan dengan seksama terlebih dahulu. Ya, refleksi akan bisa membantu Anda di sini.
Jika Anda membagi string dengan; pertama, untuk mendapatkan properti individu, Anda dapat menggunakan kode berikut untuk mendapatkan objek PropertyInfo untuk properti tertentu untuk kelas, dan kemudian menggunakan objek tersebut untuk memanipulasi objek tertentu.
String propName = "Text"; PropertyInfo pi = someObject.GetType().GetProperty(propName); pi.SetValue(someObject, "New Value", new Object[0]);
Tautan: Metode PropertyInfo.SetValue
sumber
GetMethod(methodName)
, mengurai nilai parameter, dan memanggil metode menggunakan refleksi.Menggunakan Roslyn scripting API (lebih banyak contoh di sini ):
// add NuGet package 'Microsoft.CodeAnalysis.Scripting' using Microsoft.CodeAnalysis.CSharp.Scripting; await CSharpScript.EvaluateAsync("System.Math.Pow(2, 4)") // returns 16
Anda juga dapat menjalankan kode apa pun:
var script = await CSharpScript.RunAsync(@" class MyClass { public void Print() => System.Console.WriteLine(1); }")
Dan mereferensikan kode yang dibuat di proses sebelumnya:
await script.ContinueWithAsync("new MyClass().Print();");
sumber
Tidak juga. Anda dapat menggunakan refleksi untuk mencapai apa yang Anda inginkan, tetapi itu tidak akan sesederhana di Javascript. Misalnya, jika Anda ingin menyetel bidang pribadi suatu objek menjadi sesuatu, Anda dapat menggunakan fungsi ini:
protected static void SetField(object o, string fieldName, object value) { FieldInfo field = o.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic); field.SetValue(o, value); }
sumber
Ini adalah fungsi eval di bawah c #. Saya menggunakannya untuk mengubah fungsi anonim (Ekspresi Lambda) dari sebuah string. Sumber: 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; }
sumber
Saya telah menulis proyek open source, Dynamic Expresso , yang dapat mengubah ekspresi teks yang ditulis menggunakan sintaks C # menjadi delegasi (atau pohon ekspresi). Ekspresi diurai dan diubah menjadi Pohon Ekspresi tanpa menggunakan kompilasi atau refleksi.
Anda bisa menulis sesuatu seperti:
var interpreter = new Interpreter(); var result = interpreter.Eval("8 / 2 + 2");
atau
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);
Pekerjaan saya didasarkan pada artikel Scott Gu http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx .
sumber
Semua itu pasti akan berhasil. Secara pribadi, untuk masalah khusus itu, saya mungkin akan mengambil pendekatan yang sedikit berbeda. Mungkin sesuatu seperti ini:
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 } }
Saat menggunakan pola seperti ini, Anda harus berhati-hati karena data Anda disimpan dengan referensi dan bukan dengan nilai. Dengan kata lain, jangan lakukan ini dengan orang primitif. Anda harus menggunakan rekan kelas mereka yang besar.
Saya menyadari bukan itu pertanyaannya, tetapi pertanyaannya telah dijawab dengan cukup baik dan saya pikir mungkin pendekatan alternatif dapat membantu.
sumber
Saya tidak sekarang jika Anda benar-benar ingin menjalankan pernyataan C #, tetapi Anda sudah dapat menjalankan pernyataan Javascript di C # 2.0. Pustaka sumber terbuka Jint mampu melakukannya. Ini adalah juru bahasa Javascript untuk .NET. Lulus program Javascript dan itu akan berjalan di dalam aplikasi Anda. Anda bahkan dapat mengirimkan objek C # sebagai argumen dan melakukan otomasi padanya.
Juga jika Anda hanya ingin mengevaluasi ekspresi pada properti Anda, cobalah NCalc .
sumber
Anda dapat menggunakan refleksi untuk mendapatkan properti dan memintanya. Sesuatu seperti ini:
object result = theObject.GetType().GetProperty("Property" + i).GetValue(theObject, null);
Artinya, dengan asumsi objek yang memiliki properti disebut "theObject" :)
sumber
Anda juga bisa mengimplementasikan Webbrowser, lalu memuat file html yang berisi javascript.
Kemudian Anda pergi untuk
document.InvokeScript
Metode di browser ini. Nilai kembali dari fungsi eval dapat ditangkap dan diubah menjadi semua yang Anda butuhkan.Saya melakukan ini di beberapa Proyek dan bekerja dengan sempurna.
Semoga membantu
sumber
Anda dapat melakukannya dengan fungsi prototipe:
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); }
dan seterusnya...
sumber
Menggunakan refleksi untuk mengurai dan mengevaluasi ekspresi pengikatan data terhadap objek pada waktu proses.
Metode DataBinder.Eval
sumber
Saya telah menulis sebuah paket, SharpByte.Dynamic , untuk menyederhanakan tugas menyusun dan menjalankan kode secara dinamis. Kode dapat dipanggil pada objek konteks apa pun menggunakan metode ekstensi seperti yang dijelaskan lebih lanjut di sini .
Sebagai contoh,
someObject.Evaluate<int>("6 / {{{0}}}", 3))
mengembalikan 3;
someObject.Evaluate("this.ToString()"))
mengembalikan representasi string objek konteks;
someObject.Execute(@ "Console.WriteLine(""Hello, world!""); Console.WriteLine(""This demonstrates running a simple script""); ");
menjalankan pernyataan tersebut sebagai skrip, dll.
Executable bisa didapatkan dengan mudah menggunakan metode pabrik, seperti yang terlihat pada contoh di sini - yang Anda butuhkan hanyalah kode sumber dan daftar parameter bernama yang diharapkan (token disematkan menggunakan notasi braket tiga, seperti {{{0}} }, untuk menghindari tabrakan dengan string.Format () serta sintaks mirip Handlebars):
Setiap objek yang dapat dieksekusi (skrip atau ekspresi) aman untuk thread, dapat disimpan dan digunakan kembali, mendukung logging dari dalam skrip, menyimpan informasi waktu dan pengecualian terakhir jika ditemukan, dll. Ada juga metode Copy () yang dikompilasi pada masing-masing untuk memungkinkan membuat salinan murah, yaitu menggunakan objek yang dapat dieksekusi yang dikompilasi dari skrip atau ekspresi sebagai template untuk membuat yang lain.
Overhead dari mengeksekusi skrip atau pernyataan yang sudah dikompilasi relatif rendah, di bawah mikrodetik pada perangkat keras sederhana, dan skrip dan ekspresi yang sudah dikompilasi di-cache untuk digunakan kembali.
sumber
Saya mencoba untuk mendapatkan nilai dari struktur (kelas) anggota dengan namanya. Strukturnya tidak dinamis. Semua jawaban tidak berhasil sampai saya akhirnya mendapatkannya:
public static object GetPropertyValue(object instance, string memberName) { return instance.GetType().GetField(memberName).GetValue(instance); }
Metode ini akan mengembalikan nilai anggota dengan namanya. Ia bekerja pada struktur biasa (kelas).
sumber
Anda dapat memeriksa perpustakaan Heleonix.Reflection . Ini menyediakan metode untuk mendapatkan / menyetel / memanggil anggota secara dinamis, termasuk anggota bertingkat, atau jika anggota didefinisikan dengan jelas, Anda dapat membuat pengambil / penyetel (lambda dikompilasi menjadi delegasi) yang lebih cepat daripada refleksi:
var success = Reflector.Set(instance, null, $"Property{i}", value);
Atau jika jumlah properti tidak terbatas, Anda dapat membuat setter dan menyimpannya di cache (setter lebih cepat karena mereka adalah delegasi yang dikompilasi):
var setter = Reflector.CreateSetter<object, object>($"Property{i}", typeof(type which contains "Property"+i)); setter(instance, value);
Setter bisa berjenis
Action<object, object>
tetapi instance bisa berbeda pada waktu proses, jadi Anda bisa membuat daftar setter.sumber
Sayangnya, C # tidak memiliki fasilitas asli untuk melakukan apa yang Anda minta.
Namun, program evaluasi C # saya memungkinkan untuk mengevaluasi kode C #. Ini menyediakan untuk mengevaluasi kode C # saat runtime dan mendukung banyak pernyataan C #. Faktanya, kode ini dapat digunakan dalam proyek .NET apa pun, namun, ini terbatas untuk menggunakan sintaks C #. Kunjungi situs web saya, http://csharp-eval.com , untuk detail tambahan.
sumber
jawaban yang benar adalah Anda perlu men-cache semua hasil untuk menjaga penggunaan mem0ry tetap rendah.
sebuah contoh akan terlihat seperti ini
TypeOf(Evaluate) { "1+1":2; "1+2":3; "1+3":5; .... "2-5":-3; "0+0":1 }
dan menambahkannya ke Daftar
List<string> results = new List<string>(); for() results.Add(result);
simpan id dan gunakan dalam kode
semoga ini membantu
sumber