2010-09-08 9 views
21

ho bisogno di essere in grado di ottenere qualcosa di simile a quanto segue per lavorare:IQueryable OfType <T> dove T è un tipo di runtime

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

è possibile? Sono in grado di utilizzare. NET 4 se qualcosa di nuovo in che consente questo.

+3

Si vuole porsi 'perché?' Attenzione. – leppie

+0

Deve essere IQueryable? Dal tuo esempio, IEnumerable sembra sufficiente. –

+0

@leppie Non capisco il tuo punto .. – Tablet

risposta

36

Si può chiamare da una riflessione:

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

Un'alternativa sarebbe quella di scrivere il proprio OfTypeAndToArray metodo generico di fare entrambi i bit di esso, ma quanto sopra dovrebbe funzionare.

+0

Skeet funziona, che legenda - Userò semplicemente SQL profiler per vedere se sta facendo il filtro dopo aver recuperato la raccolta o come parte della query .. a meno conosci anche la risposta! – Tablet

+1

@Shahin: Dovrebbe fare la cosa giusta - chiama "Queryable.Where" invece di "Enumerable.Where", dopo tutto. –

+0

@Skeet hai idea del motivo per cui potrebbe essere il caching dal primo set di risultati che ha ricevuto? – Tablet

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

Questo non restituirà l'intero contenuto delle risorse prima di eseguire il punto contro di esso? Usando OfType su questo contesto lo si esegue nell'SQL (sto usando Zentity) – Tablet

+0

In aggiunta a ciò che ha detto Shahin, questo è anche sbagliato per i tipi polimorfici. – Timwi

+0

Si dice che il nome dello spazio dei nomi è previsto quando provo a farlo – Tablet

8

Sembra che avrete bisogno di utilizzare Reflection qui ...

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

Grazie per il tuo aiuto! – Tablet

0

esclusivamente sulla tua domanda per uso "Generics", No, non è possibile.

Generics è una funzione di compilazione del tempo e non una scoperta di runtime. Per il runtime, è necessario utilizzare Reflection o Dynamic.

+2

Meh, non mi piace la caratterizzazione di "generici è una funzione di compilazione del tempo". È così e anche dimostrabilmente una funzionalità di runtime (a differenza di Java). –

+0

Potrebbe non piacerti, ma quello che conta è che i generici sono una funzione di compilazione del tempo. Il tipo generico è compilato con la conoscenza del T. Se puoi mostrare il contrario, ti prego di illuminarmi. – Aliostad

+0

Se non fosse una funzione runtime come potrebbe funzionare MakeGenericType? – Casey

0

che dire ...

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