使用System.Linq.Dynamic动态查询,如何将结果转为IEnumerable?
Got it, let's walk through your problem and fix it step by step. You're hitting two key roadblocks here:
- Converting the non-generic
IQueryable(returned fromDbSet.Set(Type)) to a genericIEnumerable<T>that yourPagedResponseexpects. - Using a runtime
Typevariable as a compile-time generic type parameter (sincereturnTypeis aTypeinstance, you can't directly writePagedResponse<returnType>).
Let's cover two practical solutions—one using reflection (for when you can't modify your entity classes) and a cleaner, type-safe approach (if you can add a shared interface/base class to your entities).
Solution 1: Use Reflection to Handle Dynamic Types
This works if you can't adjust your existing entity classes. We'll use reflection to convert the non-generic query result to IEnumerable<T> and instantiate the generic PagedResponse at runtime.
Here's the revised code:
Type returnType = null; switch (kwdType.ToLower()) { case "class1": returnType = typeof(TblClass1); break; case "class2": returnType = typeof(TblClass2); break; case "class3": returnType = typeof(TblClass3); break; default: // Handle invalid keyword type (throw error or return empty result) throw new ArgumentException("Invalid kwdType value", nameof(kwdType)); } // Get the non-generic query result var query = MYDB.Set(returnType).AsQueryable().Where("Active=@0", "Y"); // Convert non-generic IQueryable to IEnumerable<T> using reflection var castMethod = typeof(Enumerable).GetMethod(nameof(Enumerable.Cast)) .MakeGenericMethod(returnType); var enumerableResult = castMethod.Invoke(null, new object[] { query }) as IEnumerable; // Create the generic PagedResponse<T> instance at runtime var pagedResponseType = typeof(PagedResponse<>).MakeGenericType(returnType); var pagedResponse = Activator.CreateInstance(pagedResponseType, enumerableResult, pageIndex, pageSize); // Return the result (adjust your method's return type to object or a shared base type if needed) return pagedResponse;
Why this works:
Enumerable.Cast<T>is invoked via reflection to turn the non-genericIQueryableinto a type-specificIEnumerable<T>.Activator.CreateInstancebuilds thePagedResponse<T>instance using your runtimereturnTypeas the generic parameter.
Solution 2: Type-Safe Approach with Shared Interface/Base Class
If you can modify your entity classes, this is the better option—it avoids reflection entirely and keeps your code type-safe.
First, define a shared interface (or base class) that all your TblClass entities implement:
public interface IActiveEntity { string Active { get; set; } } // Update each entity class to implement the interface public class TblClass1 : IActiveEntity { public string Active { get; set; } // Other entity properties... } public class TblClass2 : IActiveEntity { public string Active { get; set; } // Other entity properties... }
Then rewrite your logic to use generic methods:
IEnumerable<IActiveEntity> activeEntities; switch (kwdType.ToLower()) { case "class1": activeEntities = GetActiveEntities<TblClass1>(); break; case "class2": activeEntities = GetActiveEntities<TblClass2>(); break; case "class3": activeEntities = GetActiveEntities<TblClass3>(); break; default: throw new ArgumentException("Invalid kwdType value", nameof(kwdType)); } // Now you can directly create the PagedResponse with the shared interface return new PagedResponse<IActiveEntity>(activeEntities, pageIndex, pageSize); // Helper generic method to reuse query logic private IEnumerable<T> GetActiveEntities<T>() where T : class, IActiveEntity { return MYDB.Set<T>().Where(x => x.Active == "Y"); }
Why this works:
- All entities share the
IActiveEntityinterface, so we can return a commonIEnumerable<IActiveEntity>from each switch case. - No reflection is needed—everything is validated at compile time, reducing runtime errors and making your code easier to maintain.
内容的提问来源于stack exchange,提问作者Rajeev Menon

