C# Lambda 属性值选择器作为参数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16676854/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 01:38:27  来源:igfitidea点击:

Lambda property value selector as parameter

c#vb.netlinqlambda

提问by XN16

I have a requirement to modify a method so that it has an extra parameter that will take a lambda expression that will be used on an internal object to return the value of the given property. Forgive my probable incorrect use of terminology as this is my first foray into LINQ expressions!

我需要修改一个方法,以便它有一个额外的参数,该参数将采用一个 lambda 表达式,该表达式将用于内部对象以返回给定属性的值。请原谅我可能不正确地使用术语,因为这是我第一次涉足 LINQ 表达式!

I have tried searching for an answer, but as I mentioned, my terminology seems to be off and the examples I can find are far too complex or deal with expressions for collection functions such as .Where(), which I am familiar with.

我曾尝试寻找答案,但正如我所提到的,我的术语似乎不合适,而且我能找到的示例过于复杂,或者处理诸如.Where()我熟悉的集合函数的表达式。

What I have so far (cut down version):

到目前为止我所拥有的(精简版):

class MyClass
{
    private MyObject _myObject = new MyObject() { Name = "Test", Code = "T" };

    private string MyMethod(int testParameter, ??? selector)
    {
        //return _myObject.Name;
        //return _myObject.Code;
        return ???;
    }
}

I would like to call it something like this:

我想这样称呼它:

string result = _myClassInstance.MyMethod(1, (x => x.Name));

or:

或者:

string result = _myClassInstance.MyMethod(1, (x => x.Code));

Obviously the parts which I am missing is the selectorparameter in MyMethod, how to apply it to the local variable and how to pass the required property into the method when I am invoking it.

显然,我缺少的部分是 中的selector参数MyMethod,如何将其应用于局部变量以及如何在调用它时将所需的属性传递到方法中。

Any help would be appreciated, also extra bonus points for a VB.NET solutions as well as unfortunately the final implementation needs to be in our lone VB project!

任何帮助将不胜感激,还有 VB.NET 解决方案的额外加分点,不幸的是,最终实现需要在我们单独的 VB 项目中!

采纳答案by Lee

private string MyMethod(int testParameter, Func<MyObject, string> selector)
{
    return selector(_myObject);
}

When using Funcdelegates, the last parameter is the return type and the first N-1 are the argument types. In this case, there is a single MyObjectargument to selectorand it returns a string.

使用Func委托时,最后一个参数是返回类型,前 N-1 是参数类型。在这种情况下,只有一个MyObject参数 toselector并且它返回一个string

You can invoke it like:

您可以像这样调用它:

string name = _myClassInstance.MyMethod(1, x => x.Name);
string result = _myClassInstance.MyMethod(1, x => x.Code);

Since the return type of MyMethodmatches the return type of your selectordelegate, you could make it generic:

由于返回类型MyMethodselector委托的返回类型相匹配,因此您可以将其设为通用:

private T MyMethod<T>(int testParameter, Func<MyObject, T> selector)
{
    MyObject obj = //
    return selector(obj);
}

EDIT: I don't know VB.Net but it looks like it would be:

编辑:我不知道 VB.Net 但它看起来像:

Public Function MyMethod(testParameter as Integer, selector as Func(Of MyObject, String))
    Return selector(_myObject)
End Function

and the generic version would be:

通用版本将是:

Public Function MyMethod(Of T)(testParameter as Integer, selector Func(Of MyObject, T))
    Return selector(_myObject)
End Function

回答by Reza ArabQaeni

class MyClass
{
    private MyObject _myObject = new MyObject() { Name = "Test", Code = "T" };

    private string MyMethod(int testParameter, Func<MyObject, string> selector)
    {
        return selector(_myObject );
    }
}

回答by Teejay

You can do that with a delegate of your selector:

您可以使用选择器的委托来做到这一点:

delegate string SampleDelegate(MyObject obj);

private string MyMethod(int testParameter, SampleDelegate selector)
{
    return selector(_myObject);
}

回答by Mr.Mindor

in C#

在 C# 中

The parameter type you are looking for Func

你要找的参数类型 Func

private string MyMethod(int testParameter, Func<MyClass,string> selector){
    return selector(_myObject);
}

in VB you still want Func the syntax is a little different.

在 VB 中你仍然需要 Func 语法有点不同。

Function MyMethod(ByVal testParameter As Integer, ByVal selector as Func(Of MyClass,string) as string
    return selector(_myObject)
End Function

回答by Douglas Barbin

You are probably looking for the Delegate class ("Delegate" in VB, "delegate" in C#), or one of its subtypes.

您可能正在寻找 Delegate 类(VB 中的“Delegate”,C# 中的“delegate”)或其子类型之一。

This pagehas some examples you will probably find useful, especially near the bottom of the page.

此页面包含一些您可能会觉得有用的示例,尤其是在页面底部附近。

Here is a VB example of what you would want to do:

这是您想要执行的 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

回答by Matt

I will show you a different approach that is very flexible (see DotNetFiddleat the bottom): You can easily write your own LINQfunctionsto extend existing functions or write your own functions and benefit from the power of LINQ queries.

我将向您展示一种非常灵活的不同方法(请参阅底部的DotNetFiddle):您可以轻松编写自己的LINQ函数来扩展现有函数或编写自己的函数并受益于 LINQ 查询的强大功能。

In this example, I am improving Linq's Distinctfunction in a way so you can specify a field, which is used for grouping.

在此示例中,我Distinct以某种方式改进了 Linq 的功能,以便您可以指定用于分组的字段。

Usage (Example):

用法(示例):

var myQuery=(from x in Customers select x).MyDistinct(d => d.CustomerID);

In this example the query is being grouped by CustomerIDand the first element of each group is returned.

在这个例子中,查询被分组,CustomerID并返回每个组的第一个元素。

Declaration of MyDistinct:

声明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());
    }
}

You can see that f, the 2nd parameter, is declared as Func<T, V>, so it can be used by the .GroupBystatement.

您可以看到f,第二个参数被声明为Func<T, V>,因此它可以被.GroupBy语句使用。



Coming back to the code in your question, if you have declared

回到你的问题中的代码,如果你已经声明

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"}
};

you could use that with the newly defined function MyDistinctas follows:

您可以将其与新定义的函数一起使用,MyDistinct如下所示:

var myQuery = (from x in _myObject select x).MyDistinct(d => d.Code);

which will return

这将返回

Name   Code
Test1   T
Test2   Q

名称 代码
Test1 T
Test2 Q

or you can use .MyDistinct(d => d.Name)in the query, which returns:

或者您可以.MyDistinct(d => d.Name)在查询中使用,它返回:

Name   Code
Test1   T
Test2   Q
Test5   Q

名称 代码
Test1 T
Test2 Q
Test5 Q

Notice that because MyDistinctis declared with the generics Tand V, it recognizes and uses the right object types automatically and returns MyObjectelements.

请注意,因为MyDistinct使用泛型Tand声明V,所以它会自动识别和使用正确的对象类型并返回MyObject元素。



Advanced usage

高级用法

Notice that MyDistinctalways takes the first element of each group. What if you need a condition defining which element you need?

请注意,MyDistinct始终采用每个组的第一个元素。如果您需要一个条件来定义您需要的元素怎么办?

Here's how you can do it:

您可以这样做:

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);
    }
}

This modification either allows you to use it exactly as before, i.e. by specifying one parameter like .MyDistinct(d => d.Name), but it also allows you to specify a having condition such as x => x.FirstOrDefault(y => y.Name.Contains("1")||y.Name.Contains("2"))as a second parameter like so:

此修改允许您完全像以前一样使用它,即通过指定一个参数,例如.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"))
        );

If you run this query, the result is:

如果你运行这个查询,结果是:

Name   Code
Test1   T
Test2   Q
null

名称 代码
Test1 T
Test2 Q
null

because Test5does not meet the condition (it does not contain 1 or 2), you're getting nullin the 3rd row.

因为Test5不满足条件(它不包含 1 或 2),所以你在第三行得到null

Note:If you want to expose just the condition, you can have it even simpler by implementing it as:

注意:如果您只想公开条件,您可以通过将其实现为更简单:

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));
}

In this case, the query would just look like:

在这种情况下,查询将如下所示:

var myQuery3 = (from x in _myObject select x).MyDistinct2(d => d.Name,
                    y => y.Name.Contains("1") || y.Name.Contains("2")
                    );

so you don't need to write x=>x.FirstOrDefault(... condition ...).

所以你不需要写x=>x.FirstOrDefault(... condition ...).

Try it in DotNetFiddle

在 DotNetFiddle 中尝试