我需要修改一个方法,以便它有一个额外的参数,该参数将采用将在内部对象上使用的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));
显然,我缺少的部分是selector
中的MyMethod
参数,如何将它应用于局部变量以及在调用时如何将所需属性传递给方法。 / p>
任何帮助都会受到赞赏,也是VB.NET解决方案的额外奖励点,不幸的是最终的实现需要在我们唯一的VB项目中!
答案 0 :(得分:35)
private string MyMethod(int testParameter, Func<MyObject, string> selector)
{
return selector(_myObject);
}
使用Func
个委托时,最后一个参数是返回类型,第一个N-1是参数类型。在这种情况下,MyObject
只有一个selector
参数,并返回string
。
您可以像以下一样调用它:
string name = _myClassInstance.MyMethod(1, x => x.Name);
string result = _myClassInstance.MyMethod(1, x => x.Code);
由于MyMethod
的返回类型与selector
委托的返回类型相匹配,因此您可以将其设为通用:
private T MyMethod<T>(int testParameter, Func<MyObject, T> 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
答案 1 :(得分:3)
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<T> MyDistinct<T, V>(this IEnumerable<T> query,
Func<T, V> f)
{
return query.GroupBy(f).Select(x=>x.First());
}
}
您可以看到f
(第二个参数)被声明为Func<T, V>
,因此.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
测试2问
Test5 Q
请注意,由于MyDistinct
是使用泛型T
和V
声明的,因此它会自动识别并使用正确的对象类型并返回MyObject
个元素。
高级用法
请注意,MyDistinct
始终采用每个组的第一个元素。如果您需要一个条件来定义您需要哪个元素,该怎么办?
以下是您可以这样做的方法:
public static class Extensions
{
public static IEnumerable<T> MyDistinct<T, V>(this IEnumerable<T> query,
Func<T, V> f,
Func<IGrouping<V,T>,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
测试2问
null
因为Test5
不符合条件(它不包含1或2),所以你在第3行得到 null 。
注意:如果您想公开这种情况,可以通过以下方式实现更简单:
public static IEnumerable<T> MyDistinct2<T, V>(this IEnumerable<T> query,
Func<T, V> f,
Func<T,bool> 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 ...)
。
答案 2 :(得分:2)
在C#中
您正在寻找的参数类型Func
private string MyMethod(int testParameter, Func<MyClass,string> 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
答案 3 :(得分:0)
class MyClass
{
private MyObject _myObject = new MyObject() { Name = "Test", Code = "T" };
private string MyMethod(int testParameter, Func<MyObject, string> selector)
{
return selector(_myObject );
}
}
答案 4 :(得分:0)
您可以使用选择器的代表执行此操作:
delegate string SampleDelegate(MyObject obj);
private string MyMethod(int testParameter, SampleDelegate selector)
{
return selector(_myObject);
}
答案 5 :(得分:0)
您可能正在寻找Delegate类(VB中的“Delegate”,C#中的“delegate”)或其子类型之一。
This page有一些您可能会觉得有用的示例,尤其是在页面底部附近。
以下是您想要做的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