Lambda属性值选择器作为参数
我需要修改一个方法,以便它有一个额外的参数,该参数将采用将在内部对象上使用的lambda表达式来返回给定属性的值。 原谅我可能错误地使用术语,因为这是我第一次涉足LINQ表达式!
我试图寻找答案,但正如我所提到的,我的术语似乎已经关闭,我可以找到的例子太复杂或者处理集合函数的表达式,例如我熟悉的.Where()
。
到目前为止我所拥有的(减少版本):
class MyClass { private MyObject _myObject = new MyObject() { Name = "Test", Code = "T" }; private string MyMethod(int testParameter, ??? selector) { //return _myObject.Name; //return _myObject.Code; return ???; } }
我想称之为:
string result = _myClassInstance.MyMethod(1, (x => x.Name));
要么:
string result = _myClassInstance.MyMethod(1, (x => x.Code));
显然,我缺少的部分是MyMethod
的selector
参数,如何将它应用于局部变量以及在调用时如何将必需的属性传递给方法。
任何帮助将不胜感激,也是VB.NET解决方案的额外奖励点,不幸的是最终的实现需要在我们唯一的VB项目中!
private string MyMethod(int testParameter, Func selector) { return selector(_myObject); }
使用Func
委托时,最后一个参数是返回类型,第一个N-1是参数类型。 在这种情况下, selector
有一个MyObject
参数,它返回一个string
。
您可以像下面这样调用它:
string name = _myClassInstance.MyMethod(1, x => x.Name); string result = _myClassInstance.MyMethod(1, x => x.Code);
由于MyMethod
的返回类型与selector
委托的返回类型匹配,因此您可以将其设为通用:
private T MyMethod(int testParameter, Func selector) { MyObject obj = // return selector(obj); }
编辑:我不知道VB.Net但看起来它会是:
Public Function MyMethod(testParameter as Integer, selector as Func(Of MyObject, String)) Return selector(_myObject) End Function
通用版本将是:
Public Function MyMethod(Of T)(testParameter as Integer, selector Func(Of MyObject, T)) Return selector(_myObject) End Function
LINQ就是查询列表。 我看到的答案不是处理查询,因此我将向您展示一种非常灵活的方法,因为您可以轻松编写自己的Linq函数 ,以扩展现有函数或编写自己的函数。
在这个例子中,我正在改进Linq的Distinct
函数,以便您可以指定一个用于分组的字段。
用法(示例):
var myQuery=(from x in Customers select x).MyDistinct(d => d.CustomerID);
在此示例中,查询按CustomerID
分组,并返回每个组的第一个元素。
MyDistinct
宣言:
public static class Extensions { public static IEnumerable MyDistinct(this IEnumerable query, Func f) { return query.GroupBy(f).Select(x=>x.First()); } }
您可以看到第二个参数f
被声明为Func
,因此它可以被.GroupBy
语句使用。
如果您已经声明,请回到您问题中的代码
class MyObject { public string Name; public string Code; } private MyObject[] _myObject = { new MyObject() { Name = "Test1", Code = "T"}, new MyObject() { Name = "Test2", Code = "Q"}, new MyObject() { Name = "Test2", Code = "T"}, new MyObject() { Name = "Test5", Code = "Q"} };
你可以使用新定义的函数MyDistinct
,如下所示:
var myQuery = (from x in _myObject select x).MyDistinct(d => d.Code);
将返回
名称代码
Test1 T
Test2 Q.
或者你可以在查询中使用.MyDistinct(d => d.Name)
,它返回:
名称代码
Test1 T
Test2 Q.
Test5 Q.
请注意,因为MyDistinct
是使用genericsT
和V
声明的,所以它会自动识别并使用正确的对象类型并返回MyObject
元素。
高级用法
请注意, MyDistinct
始终采用每个组的第一个元素。 如果您需要一个条件来定义您需要哪个元素怎么办?
以下是您可以这样做的方法:
public static class Extensions { public static IEnumerable MyDistinct(this IEnumerable query, Func f, Func,T> h=null) { if (h==null) h=(x => x.First()); return query.GroupBy(f).Select(h); } }
这个修改允许你像以前一样使用它,即通过指定一个参数,如.MyDistinct(d => d.Name)
,但它也允许你指定一个条件,如x => x.FirstOrDefault(y => y.Name.Contains("1")||y.Name.Contains("2"))
作为第二个参数,如下所示:
var myQuery2 = (from x in _myObject select x).MyDistinct(d => d.Name, x=>x.FirstOrDefault(y=>y.Name.Contains("1")||y.Name.Contains("2")) );
如果运行此查询,结果为:
名称代码
Test1 T
Test2 Q.
空值
因为Test5
不符合条件(它不包含1或2),所以你在第3行得到null 。
注意:如果您只想暴露条件,可以通过将其实现为更简单:
public static IEnumerable MyDistinct2(this IEnumerable query, Func f, Func h=null ) { if (h == null) h = (y => true); return query.GroupBy(f).Select(x=>x.FirstOrDefault(h)); }
在这种情况下,查询将如下所示:
var myQuery3 = (from x in _myObject select x).MyDistinct2(d => d.Name, y => y.Name.Contains("1") || y.Name.Contains("2") );
所以你不需要写x=>x.FirstOrDefault(... condition ...)
。
在C#中
您正在寻找Func的参数类型
private string MyMethod(int testParameter, Func selector){ return selector(_myObject); }
在VB中你仍然希望Func的语法有点不同。
Function MyMethod(ByVal testParameter As Integer, ByVal selector as Func(Of MyClass,string) as string return selector(_myObject) End Function
class MyClass { private MyObject _myObject = new MyObject() { Name = "Test", Code = "T" }; private string MyMethod(int testParameter, Func selector) { return selector(_myObject ); } }
您可以使用选择器的委托执行此操作:
delegate string SampleDelegate(MyObject obj); private string MyMethod(int testParameter, SampleDelegate selector) { return selector(_myObject); }
您可能正在寻找Delegate类(VB中的“Delegate”,C#中的“delegate”)或其子类型之一。
这个页面有一些你可能会觉得有用的例子,特别是在页面底部附近。
这是您想要做的VB示例:
Public Class MyClass Private Property _myObject As MyObject = New MyObject With {.Name = "Test", .Code = "T"} Private Function MyMethod(testParameter As Integer, selector As Func(Of MyObject, String)) As String Return selector(_myObject).ToString End Function End Class