我最近发现了一个静态方法,声明为:
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)如果两个代码块是等价的,使用前者比后者有什么好处?
好的,为了清楚起见,我将再次写出两个(并稍微修改方法以使其更短)
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语法以一种有趣的方式对一个匿名委托进行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事件系统的基石.还有一些阅读清理一下:
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视为另一种方法中的变量.然而,在这个特定的例子中,它们或多或少具有相同的好处(尽管后者更易于理解).
在大多数情况下,它们在功能上似乎是等效的。事实上,您可以将普通方法作为变量传递。
但也存在一些细微的差异,例如能够将函数重新定义为其他函数。如果您使用反射,它可能也会有所不同,例如它可能不会在类的方法列表中返回。(反射部分不是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# 中拥有真正的一流函数...有趣...
| 归档时间: |
|
| 查看次数: |
3520 次 |
| 最近记录: |