IQueryable OfType where T is a runtime Type

后端 未结 7 607
旧巷少年郎
旧巷少年郎 2020-12-14 01:52

I need to be able to get something similar to the following to work:

Type type = ??? // something decided at runtime with .GetType or typeof;
object[] entity         


        
相关标签:
7条回答
  • 2020-12-14 02:35

    what about ...

        public static IList OfTypeToList(this IEnumerable source, Type type)
        {
            if (type == null)
                throw new ArgumentNullException(nameof(type));
            return
                (IList) Activator.CreateInstance(
                    typeof(List<>)
                       .MakeGenericType(type),
                    typeof(System.Linq.Enumerable)
                       .GetMethod(nameof(System.Linq.Enumerable.OfType),
                                  BindingFlags.Static | BindingFlags.Public)
                       .MakeGenericMethod(type)
                       .Invoke(null, new object[] { source }));
        }
    
    0 讨论(0)
  • 2020-12-14 02:41

    Looks like you’ll need to use Reflection here...

    public static IEnumerable<object> DyamicOfType<T>(
            this IQueryable<T> input, Type type)
    {
        var ofType = typeof(Queryable).GetMethod("OfType",
                         BindingFlags.Static | BindingFlags.Public);
        var ofTypeT = ofType.MakeGenericMethod(type);
        return (IEnumerable<object>) ofTypeT.Invoke(null, new object[] { input });
    }
    
    Type type = // ...;
    var entityList = context.Resources.DynamicOfType(type).ToList();
    
    0 讨论(0)
  • 2020-12-14 02:41

    A solution to handle multiple types is

            public static IQueryable<TEntity> OfTypes<TEntity>(this DbSet<TEntity> query, IEnumerable<Type> types )  where TEntity : class
                {
                        if( types.Count() == 0 ) return query;
    
                        var lambda = GetOfOnlyTypesPredicate( typeof(TEntity), types.ToArray() );
                        return query.OfType<TEntity>().Where( lambda as Expression<Func<TEntity,bool>>);
    
                }
    
    
                public static LambdaExpression GetOfOnlyTypesPredicate( Type baseType, Type[] allowed )
                {
                        ParameterExpression param = Expression.Parameter( baseType, "typeonlyParam" );
                        Expression merged = Expression.TypeIs( param, allowed[0] );
                        for( int i = 1; i < allowed.Length; i++ )
                                merged = Expression.OrElse( merged, Expression.TypeIs( param, allowed[i] ));
                        return Expression.Lambda( merged, param );
    
    0 讨论(0)
  • 2020-12-14 02:45

    Based on @Jon Skeet's answer, here's a LINQ extension method:

    public static class QueryableExtensions
    {
        public static IQueryable<TSource> OfType<TSource>(this IQueryable<TSource> queryable,
            Type runtimeType)
        {
            var method = typeof(Queryable).GetMethod(nameof(Queryable.OfType));
            var generic = method.MakeGenericMethod(new[] { runtimeType });
            return (IQueryable<TSource>)generic.Invoke(null, new[] { queryable });
        }
    }
    
    0 讨论(0)
  • 2020-12-14 02:46

    Purely on your question to use "Generics", No it is not possible.

    Generics is a compile time feature, and not a runtime discovery. For runtime, you need to use Reflection or Dynamic.

    0 讨论(0)
  • 2020-12-14 02:51

    You can call it by reflection:

    MethodInfo method = typeof(Queryable).GetMethod("OfType");
    MethodInfo generic = method.MakeGenericMethod(new Type[]{ type });
    // Use .NET 4 covariance
    var result = (IEnumerable<object>) generic.Invoke
          (null, new object[] { context.Resources });
    object[] array = result.ToArray();
    

    An alternative would be to write your own OfTypeAndToArray generic method to do both bits of it, but the above should work.

    0 讨论(0)
提交回复
热议问题