Szukam sposobu wywoływania ogólnej metody z wyrażeniem lambda, które wywołuje Contains w tablicy elementów.Odbicie, aby wywołać metodę ogólną z parametrem wyrażenia lambda
W tym przypadku używam metody Entity Framework Where, ale scenariusz można zastosować w innych IEnumerables.
Muszę zadzwonić do ostatniej linii powyższego kodu przez Reflection, więc mogę użyć dowolnego typu i dowolnej właściwości, aby przejść do metody 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?**
W badaniach, zauważyłem, że powinienem użyć getMethod, MakeGenericType i ekspresja, aby osiągnąć to, ale nie mogę dowiedzieć się, jak to zrobić. Byłoby bardzo pomocne mieć ten przykład, aby zrozumieć, jak Reflection działa z koncepcjami Lambda i Generic.
Zasadniczo celem jest napisać poprawną wersję funkcji takiego:
//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
}
Nie jestem pewien, czy inne kwestie rozwiązać ten scenariusz, ponieważ nie sądzę, mogę jasno zrozumieć, w jaki sposób Wyrażenia działają.
Aktualizacja:
Nie mogę korzystać Generics bo tylko rodzaj i właściwości mają zostać zbadane (w Zawiera) w czasie wykonywania. W pierwszym przykładzie kodu, załóżmy, że "MyType" nie jest znany podczas kompilacji. W drugim przykładzie kodu typ mógł zostać przekazany jako parametr do funkcji GetFilteredList lub mógł zostać uzyskany za pomocą Reflection (GetGenericArguments).
Dzięki,
Dla pewności, poprawa może być sposobem wywołania Invoke zamiast DynamicInvoke w instrukcji return. – natenho
jesteś bohaterem! :) – AmmarCSE
Dwa lata później, wciąż jest to najlepszy przykład dynamicznego tworzenia ekspresji, jaki znalazłem. Dodam, że jest o wiele szybszy, jeśli zmienisz typ na 'IQueryable' zamiast' IEnumerable', ponieważ zapytanie nie jest wymuszone wykonać natychmiast po stronie klienta i zamiast tego jest przekazywane do źródła danych (np. wykonywane przez serwer SQL przy użyciu Linq-SQL) –