有人可以解释这个C#lambda语法吗?

Roa*_*rth 10 c#

我最近发现了一个静态方法,声明为:

public class Foo
{
  public static Func<HtmlHelper, PropertyViewModel, string> Render = (a, b) =>
  {
    a.RenderPartial(b);
    return "";
  };
}
Run Code Online (Sandbox Code Playgroud)

Intellisense建议使用(例如):

string s = Foo.Render(htmlHelper, propertyViewModel);
Run Code Online (Sandbox Code Playgroud)

那么看起来以下是等价的:

public static string Render(HtmlHelper a, PropertyViewModel b)
{
  a.RenderPartial(b);
  return "";
}
Run Code Online (Sandbox Code Playgroud)

A)第一种风格的名称是什么?我意识到它正在使用lambdas; 这=是绊倒我的标志.我无法将其标记化;)

B)如果两个代码块等价的,使用前者比后者有什么好处?

Jus*_*tin 7

好的,为了清楚起见,我将再次写出两个(并稍微修改方法以使其更短)

public static Func<HtmlHelper, PropertyViewModel, string> RenderDelegate = (a, b) =>
{
    return a.RenderPartial(b);
};

public static string RenderMethod(HtmlHelper a, PropertyViewModel b)
{
    return a.RenderPartial(b);
}
Run Code Online (Sandbox Code Playgroud)

首先要注意的RenderDelegate是(正如S. DePouw所写),只是一种使用lambda语法编写以下内容的奇特方法:

public static Func<HtmlHelper, PropertyViewModel, string> RenderDelegate = 
delegate(HtmlHelper a, PropertyViewModel b)
{
    return a.RenderPartial(b);
};
Run Code Online (Sandbox Code Playgroud)

RenderMethod和之间的区别RenderDelegate是,这RenderMethod是一种方法,wheras RenderDelegate是委托,或者更具体地说是委托类型的字段.这意味着可以将RenderDelegate分配给.

什么是代表?

代表是一种类型.从MSDN文档:

委托是一种定义方法签名的类型,可以与具有兼容签名的任何方法相关联.

本质上,您可以将委托视为方法的引用/指针,但委托指向的方法必须与委托所期望的签名相匹配.因此,例如Func<HtmlHelper, PropertyViewModel, string>是一个委托,它需要具有签名的方法,string MyMethod(HtmlHelper, PropertyViewModel)因此我们能够将具有该签名的方法分配给该委托,如下所示:

RenderDelegate = RenderMethod;
Run Code Online (Sandbox Code Playgroud)

重要的是要注意委托类型(注意大写D)和委托关键字(小写d)之间的区别.在你的例子中,你使用Func<>通用对象来压缩你的代码,但是这里有什么模糊的东西. Func<HtmlHelper, PropertyViewModel, string>是一个继承自的类型Delegate,您可以使用delegate关键字来表示等效类型:

delegate string MyFunction<HtmlHelper helper, PropertyViewModel string>;
static MyFunction RenderDelegate = RenderMethod;
Run Code Online (Sandbox Code Playgroud)

匿名方法

当我们在第一个例子中分配RenderDelegate时,我们没有将RenderDelegate设置为现有的命名方法,而是我们在线声明了一个新方法.这称为匿名方法,因为我们能够传递代码块(也使用delegate关键字声明)作为委托参数:

Lambda函数

回到原始语法 - 您的示例使用lambda语法以一种有趣的方式对一个匿名委托进行delcare.Lambda表达式是声明在处理列表时通常可以使用的短内联方法的好方法,例如假设我们想要按名称对HtmlHelper对象列表进行排序.这样做的方法是传递一个将两个HtmlHelper对象与列表Sort方法进行比较的Delegate,然后sort方法使用该委托来比较和排序列表中的元素:

static int MyComparison(HtmlHelper x, HtmlHelper y)
{
    return x.Name.CompareTo(y.Name);
}

static void Main()
{
    List<HtmlHelper> myList = GetList();
    myList.Sort(MyComparison);
}
Run Code Online (Sandbox Code Playgroud)

为了避免散布大量的短方法,可以使用匿名方法对排序方法进行在线处理.对于这一点而言,真正有用的是内联方法可以访问在包含范围中声明的变量:

int myInt = 12;
List<HtmlHelper> myList = GetList();
myList.Sort(
    delegate (HtmlHelper x, HtmlHelper y)
    {
        return x.Name.CompareTo(y.Name) - myInt;
    });
Run Code Online (Sandbox Code Playgroud)

然而,这仍然相当多的打字,所以lambda sytax诞生了,现在你可以这样做:

List<HtmlHelper> myList = GetList();
myList.Sort((x, y) => {return x.Name.CompareTo(y.Name)});
Run Code Online (Sandbox Code Playgroud)

然而,以这种方式宣布"正常"方法似乎对我来说完全没有意义(并让我的眼睛流血)

代表们非常有用,并且(除其他外)是.Net事件系统的基石.还有一些阅读清理一下:


Sco*_*ott 5

A)风格是使用代表的风格.以下是等效的:

public static Func<HtmlHelper, PropertyViewModel, string> Render = 
delegate(HtmlHelper a, PropertyViewModel b)
{
    a.RenderPartial(b);
    return "";
};
Run Code Online (Sandbox Code Playgroud)

B)好处是你可以将Render视为另一种方法中的变量.然而,在这个特定的例子中,它们或多或少具有相同的好处(尽管后者更易于理解).

  • 可以将任何方法组传递给期望委托的方法.第一种风格没有独特的优势. (3认同)
  • @dtb,我不会说它没有独特的优势.声明一个常规方法使该方法只读.如果它被声明为Func类型的静态变量,则可以在运行时更改"方法". (2认同)

Dav*_*vy8 2

在大多数情况下,它们在功能上似乎是等效的。事实上,您可以将普通方法作为变量传递。

但也存在一些细微的差异,例如能够将函数重新定义为其他函数。如果您使用反射,它可能也会有所不同,例如它可能不会在类的方法列表中返回。(反射部分不是100%确定)

下面显示了将方法作为变量传递,以及第二种方法如何允许重新定义 Func,如果它是普通方法,则这是不可能的。

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(GetFunc());   //Prints the ToString of a Func<int, string>
        Console.WriteLine(Test(5));     //Prints "test"
        Console.WriteLine(Test2(5));    //Prints "test"
        Test2 = i => "something " + i;
        Console.WriteLine(Test2(5));    //Prints "something 5"
        //Test = i => "something " + i; //Would cause a compile error

    }

    public static string Test(int a)
    {
        return "test";
    }

    public static Func<int, string> Test2 = i =>
    {
        return "test";
    };

    public static Func<int, string> GetFunc()
    {
        return Test;
    }
}
Run Code Online (Sandbox Code Playgroud)

这让我开始思考...如果所有方法都以这种方式声明,那么您可以在 C# 中拥有真正的一流函数...有趣...