Gunakan pepohon ungkapan LINQ untuk memilih jenis tanpa nama secara dinamik
Pengenalan
Pokok ekspresi LINQ menyediakan mekanisme yang berkuasa untuk mencipta dan mengubah suai pertanyaan secara dinamik. Keperluan biasa ialah memilih jenis tanpa nama dengan berbilang sifat. Walaupun memilih satu sifat agak mudah, mentakrifkan berbilang sifat dalam lambda terpilih boleh menimbulkan cabaran.
Penyelesaian menggunakan pelepasan terpantul
Untuk menyelesaikan masalah ini, kami boleh menggunakan pelepasan reflektif dan kelas tambahan untuk menjana jenis tanpa nama secara dinamik. Kod berikut menunjukkan cara untuk mencapai ini:
Kaedah SelectDynamic
public static IQueryable SelectDynamic(this IQueryable source, IEnumerable<string> fieldNames) { // 创建属性名称和相应属性信息的字典 Dictionary<string, PropertyInfo> sourceProperties = fieldNames.ToDictionary(name => name, name => source.ElementType.GetProperty(name)); // 生成动态类型 Type dynamicType = LinqRuntimeTypeBuilder.GetDynamicType(sourceProperties.Values); // 创建表达式树 ParameterExpression sourceItem = Expression.Parameter(source.ElementType, "t"); IEnumerable<MemberBinding> bindings = dynamicType.GetFields().Select(p => Expression.Bind(p, Expression.Property(sourceItem, sourceProperties[p.Name]))).OfType<MemberBinding>(); Expression selector = Expression.Lambda( Expression.MemberInit( Expression.New(dynamicType.GetConstructor(Type.EmptyTypes)), bindings ), sourceItem ); // 返回带有新select表达式的查询 return source.Provider.CreateQuery( Expression.Call( typeof(Queryable), "Select", new Type[] { source.ElementType, dynamicType }, Expression.Constant(source), selector ) ); }
Kelas LinqRuntimeTypeBuilder
public static class LinqRuntimeTypeBuilder { // ... public static Type GetDynamicType(IEnumerable<PropertyInfo> fields) { // ... string className = GetTypeKey(fields); // 修改参数类型 TypeBuilder typeBuilder = moduleBuilder.DefineType(className, TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Serializable); foreach (var field in fields) typeBuilder.DefineField(field.Name, field.PropertyType, FieldAttributes.Public); // 使用field.Name 和 field.PropertyType return typeBuilder.CreateType(); } // ... }
Contoh penggunaan
Untuk memilih jenis tanpa nama dengan berbilang sifat, gunakan sintaks berikut:
var v = from c in Countries where c.City == "London" select new { c.Name, c.Population };
Kini anda boleh mengakses sifat jenis tanpa nama seperti mana-mana contoh lain:
Console.WriteLine(v.Name); Console.WriteLine(v.Population);
Nota: Coretan kod di atas perlu ditambah dengan pelaksanaan lengkap kelas LinqRuntimeTypeBuilder
, termasuk GetTypeKey
dan kaedah pembantu lain yang mungkin diperlukan. Pelaksanaan lengkap adalah kompleks dan memerlukan pengendalian pelbagai pengecualian dan pemeriksaan jenis. Ini hanyalah contoh ringkas untuk menggambarkan idea teras. Dalam aplikasi sebenar, penambahbaikan dan pengendalian ralat perlu dijalankan mengikut keperluan tertentu. Di samping itu, secara langsung menggunakan pelepasan terpantul untuk membina jenis dinamik boleh menjejaskan prestasi, dan kebaikan dan keburukan harus ditimbang berdasarkan situasi sebenar.
Atas ialah kandungan terperinci Bagaimana untuk Memilih Jenis Tanpa Nama Secara Dinamik dengan Pelbagai Sifat Menggunakan Pokok Ungkapan LINQ?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!