利用LINQ表達式樹動態選擇匿名型別
引言
LINQ表達式樹提供了一種強大的機制,用於動態建立和修改查詢。一個常見的需求是選擇具有多個屬性的匿名類型。雖然選擇單一屬性相對簡單,但在select lambda中定義多個屬性可能會帶來挑戰。
使用反射發射的解決方案
為了解決這個問題,我們可以利用反射發射和輔助類別來動態產生匿名類型。以下程式碼示範如何實現這一點:
SelectDynamic方法
<code class="language-csharp">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 ) ); }</code>
LinqRuntimeTypeBuilder類別
<code class="language-csharp">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(); } // ... }</code>
範例用法
要選擇具有多個屬性的匿名類型,請使用下列語法:
<code class="language-csharp">var v = from c in Countries where c.City == "London" select new { c.Name, c.Population };</code>
您現在可以像存取任何其他實例一樣存取匿名類型的屬性:
<code class="language-csharp">Console.WriteLine(v.Name); Console.WriteLine(v.Population);</code>
注意: 以上程式碼片段需要補充 LinqRuntimeTypeBuilder
類別的完整實現,包括 GetTypeKey
和其他可能需要的輔助方法。 完整的實作較為複雜,需要處理各種異常情況和類型檢查。 這只是一個簡化的範例,用於說明核心思想。 在實際應用中,需要根據具體需求進行完善和錯誤處理。 此外,直接使用反射發射來建構動態類型可能會影響效能,應根據實際情況權衡利弊。
以上是如何使用 LINQ 表達式樹動態選擇具有多個屬性的匿名類型?的詳細內容。更多資訊請關注PHP中文網其他相關文章!