2010-09-08 15 views
21

Je dois être en mesure d'obtenir quelque chose de semblable à ce qui suit au travail:IQueryable OfType <T> où T est un type d'exécution

Type type = ??? // something decided at runtime with .GetType or typeof; 
object[] entityList = context.Resources.OfType<type>().ToList(); 

Est-ce possible? Je suis capable d'utiliser .NET 4 si quelque chose de nouveau dans cela permet cela.

+3

Vous voulez vous demander 'pourquoi?' Attentivement. – leppie

+0

Doit-il être IQueryable? De votre exemple, IEnumerable semble suffisant. –

+0

@leppie Je ne comprends pas votre point de vue .. – Tablet

Répondre

36

Vous pouvez l'appeler par la réflexion:

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(); 

Une alternative serait d'écrire votre propre OfTypeAndToArray méthode générique pour faire les deux bits de celui-ci, mais devrait fonctionner au-dessus.

+0

Skeet ça marche, quelle légende - Je vais juste utiliser SQL profileer pour voir s'il fait le filtrage après avoir récupéré la collection ou dans le cadre de la requête .. vous connaissez la réponse à cela aussi! – Tablet

+1

@Shahin: Il devrait faire la bonne chose - il appelle 'Queryable.Where' au lieu de' Enumerable.Where', après tout. –

+0

@Skeet avez-vous une idée de la raison pour laquelle il peut être mis en cache à partir du premier jeu de résultats reçu? – Tablet

-1
object[] entityList = context.Resources 
           .Where(t=> t.GetType() == type) 
           .ToArray(); 
+0

Est-ce que cela ne retournera pas tout le contenu des ressources avant d'exécuter l'où contre? Utiliser OfType sur ce contexte l'exécute dans le SQL (j'utilise Zentity) – Tablet

+0

En plus de ce que Shahin a dit, c'est aussi faux pour les types polymorphes. – Timwi

+0

On dit que le nom de l'espace de nommage est attendu quand j'essaye de le faire – Tablet

8

On dirait que vous aurez besoin d'utiliser la réflexion ici ...

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

Merci pour votre aide! – Tablet

0

sur votre Purement question utilisation « Génériques », Non, il est impossible. Generics est une fonctionnalité de compilation et non une découverte d'exécution. Pour l'exécution, vous devez utiliser Reflection ou Dynamic.

+2

Meh, je n'aime pas la caractérisation de "génériques est une fonction de compilation". C'est cela et aussi manifestement une fonctionnalité d'exécution (contrairement à Java). –

+0

Vous ne pouvez pas l'aimer mais ce qui importe est que les génériques sont une fonction de compilation. Type générique est compilé avec la connaissance de la T. Si vous pouvez montrer le contraire, s'il vous plaît éclairer moi. – Aliostad

+0

Si ce n'était pas une fonctionnalité d'exécution, comment MakeGenericType pourrait-il fonctionner? – Casey

0

... Qu'en est-

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 })); 
    }