Sto cercando un modo per chiamare un metodo generico con un'espressione lambda che chiama Contains in una matrice di elementi.Reflection per chiamare il metodo generico con parametro espressione lambda
In questo caso sto utilizzando il metodo Entity Framework Where, ma lo scenario potrebbe essere applicato in altri oggetti IEnumer.
Devo chiamare l'ultima riga del codice sopra tramite Reflection, così posso usare qualsiasi tipo e qualsiasi proprietà per passare al metodo Contains.
var context = new TestEntities();
var items = new[] {100, 200, 400, 777}; //IN list (will be tested through Contains)
var type = typeof(MyType);
context.Set(type).Where(e => items.Contains(e.Id)); //**What is equivalent to this line using Reflection?**
Nella ricerca, ho notato che dovrei usare GetMethod, MakeGenericType ed Expression per conseguire tale, ma non riuscivo a capire come farlo. Sarebbe molto utile avere questo esempio così posso capire come funziona Reflection con i concetti Lambda e Generico.
In sostanza l'obiettivo è quello di scrivere una versione corretta di una funzione come questa:
//Return all items from a IEnumerable(target) that has at least one matching Property(propertyName)
//with its value contained in a IEnumerable(possibleValues)
static IEnumerable GetFilteredList(IEnumerable target, string propertyName, IEnumerable searchValues)
{
return target.Where(t => searchValues.Contains(t.propertyName));
//Known the following:
//1) This function intentionally can't be compiled
//2) Where function can't be called directly from an untyped IEnumerable
//3) t is not actually recognized as a Type, so I can't access its property
//4) The property "propertyName" in t should be accessed via Linq.Expressions or Reflection
//5) Contains function can't be called directly from an untyped IEnumerable
}
//Testing environment
static void Main()
{
var listOfPerson = new List<Person> { new Person {Id = 3}, new Person {Id = 1}, new Person {Id = 5} };
var searchIds = new int[] { 1, 2, 3, 4 };
//Requirement: The function must not be generic like GetFilteredList<Person> or have the target parameter IEnumerable<Person>
//because the I need to pass different IEnumerable types, not known in compile-time
var searchResult = GetFilteredList(listOfPerson, "Id", searchIds);
foreach (var person in searchResult)
Console.Write(" Found {0}", ((Person) person).Id);
//Should output Found 3 Found 1
}
Non sono sicuro se le altre domande affrontare questo scenario, perché non credo che avrei potuto chiaramente capire come Le espressioni funzionano.
Aggiornamento:
non posso usare Generics perché ho solo il tipo e la proprietà da testare (in Contiene) in fase di esecuzione. Nel primo esempio di codice, supponiamo che "MyType" non sia noto al momento della compilazione. Nel secondo esempio di codice, il tipo potrebbe essere passato come parametro alla funzione GetFilteredList o potrebbe essere ottenuto tramite Reflection (GetGenericArguments).
Grazie,
Solo per la cronaca, un miglioramento potrebbe essere un modo per chiamare Invoke anziché DynamicInvoke nell'istruzione return. – natenho
sei un eroe! :) – AmmarCSE
2 anni dopo, è ancora il miglior esempio di creazione di espressioni dinamiche che ho trovato. Aggiungerò che è molto più veloce se si cambia il tipo in 'IQueryable' piuttosto che in' IEnumerable', poiché la query non è forzata da eseguire immediatamente sul lato client e viene invece trasferito all'origine dati (ad esempio eseguito dal server SQL quando si utilizza Linq-to-SQL) –