gpt4 book ai didi

c# - 使用 lambda 表达式参数调用泛型方法的反射

转载 作者:太空狗 更新时间:2023-10-29 20:51:36 26 4
gpt4 key购买 nike

我正在寻找一种方法来调用带有 lambda 表达式的泛型方法,该表达式调用项目数组中的 Contains。

在这种情况下,我使用的是 Entity Framework Where 方法,但该场景可以应用于其他 IEnumerables。

我需要通过反射调用上面代码的最后一行,这样我就可以使用任何类型和任何属性传递给 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?**

在研究中,我注意到我应该使用 GetMethod、MakeGenericType 和 Expression 来实现这一点,但我不知道该怎么做。拥有此示例会非常有帮助,这样我就可以了解反射如何与 Lambda 和泛型概念一起工作。

基本上,目标是编写一个正确版本的函数,如下所示:

//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
}

我不确定其他问题是否解决了这种情况,因为我认为我无法清楚地理解表达式的工作原理。

更新:

我不能使用泛型,因为我只有在运行时要测试的类型和属性(在 Contains 中)。在第一个代码示例中,假设“MyType”在编译时未知。在第二个代码示例中,类型可以作为参数传递给 GetFilteredList 函数,也可以通过反射 (GetGenericArguments) 获取。

谢谢,

最佳答案

经过广泛的研究和对表达式的大量研究后,我可以自己编写一个解决方案。它当然可以改进,但完全符合我的要求。希望它可以帮助其他人。

//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)
{
//Get target's T
var targetType = target.GetType().GetGenericArguments().FirstOrDefault();
if (targetType == null)
throw new ArgumentException("Should be IEnumerable<T>", "target");

//Get searchValues's T
var searchValuesType = searchValues.GetType().GetGenericArguments().FirstOrDefault();
if (searchValuesType == null)
throw new ArgumentException("Should be IEnumerable<T>", "searchValues");

//Create a p parameter with the type T of the items in the -> target IEnumerable<T>
var containsLambdaParameter = Expression.Parameter(targetType, "p");

//Create a property accessor using the property name -> p.#propertyName#
var property = Expression.Property(containsLambdaParameter, targetType, propertyName);

//Create a constant with the -> IEnumerable<T> searchValues
var searchValuesAsConstant = Expression.Constant(searchValues, searchValues.GetType());

//Create a method call -> searchValues.Contains(p.Id)
var containsBody = Expression.Call(typeof(Enumerable), "Contains", new[] { searchValuesType }, searchValuesAsConstant, property);

//Create a lambda expression with the parameter p -> p => searchValues.Contains(p.Id)
var containsLambda = Expression.Lambda(containsBody, containsLambdaParameter);

//Create a constant with the -> IEnumerable<T> target
var targetAsConstant = Expression.Constant(target, target.GetType());

//Where(p => searchValues.Contains(p.Id))
var whereBody = Expression.Call(typeof(Enumerable), "Where", new[] { targetType }, targetAsConstant, containsLambda);

//target.Where(p => searchValues.Contains(p.Id))
var whereLambda = Expression.Lambda<Func<IEnumerable>>(whereBody).Compile();

return whereLambda.Invoke();
}

关于c# - 使用 lambda 表达式参数调用泛型方法的反射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17414332/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com