LINQ 式ツリーを使用して匿名型を動的に選択する
はじめに
LINQ 式ツリーは、クエリを動的に作成および変更するための強力なメカニズムを提供します。一般的なニーズは、複数のプロパティを持つ匿名型を選択することです。単一のプロパティを選択するのは比較的簡単ですが、選択ラムダで複数のプロパティを定義すると課題が生じる可能性があります。
反射放射を使用したソリューション
この問題を解決するには、反射放出クラスと補助クラスを使用して匿名型を動的に生成します。次のコードは、これを実現する方法を示しています。
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 中国語 Web サイトの他の関連記事を参照してください。