alb*_*jan 13 .net c# generics lambda functor
我似乎无法绕过他们.
据我所知,它是动态地向类添加逻辑.框架内的课程是否为此准备好了?
我为什么要扩展类并在扩展中添加它的功能.我将在全球范围内访问,并且更容易维护.
我读过有4种仿函数类型:
Comparer
Closure
谓词
变压器
我们应该处理它们中的每一个.
ps在vb中有类似的东西吗?
所以我可以说我认为lambda表达式是仿函数.这为我清理了一些东西:)(呵呵)
但我问了这个问题,因为我遇到了另一种类型的fucntors,即这些:
delegate void FunctorDelegate(int value);
class Addition {
FunctorDelegate _delegate;
public Addition AddDelegate(FunctorDelegate deleg) {
_delegate += deleg;
return this;
}
public int AddAllElements(IList< int> list) {
int runningTotal = 0;
foreach( int value in list) {
runningTotal += value;
_delegate(value);
}
return runningTotal;
}
}
Run Code Online (Sandbox Code Playgroud)
然后用这个调用它:
int runningTotal = new Addition()
.AddDelegate(new FunctorDelegate(
delegate(int value) {
if ((value % 2) == 1) {
runningOddTotal += value;
}
}))
.AddDelegate(new FunctorDelegate(
delegate(int value) {
if ((value % 2) == 0) {
runningEvenTotal += value;
}
}))
.AddAllElements(list);
Run Code Online (Sandbox Code Playgroud)
所以没有花哨的lambda风格的东西.
现在我有了这个例子,但是为什么这是一个"好"的解决方案并不清楚.
作为程序员的快捷方式,代理人(仿函数)是否在大多数情况下用作lambda表达式或匿名方法?据我所知,只有少数情况下他们实际上是问题的首选.
Dan*_*ker 23
我认为你混淆了不同语言的术语.您似乎在C++或Java意义上使用"Functor",例如,请参阅维基百科页面.在C++中,它是一个类的对象,它重载了函数调用操作符,因此它可以用作函数但是具有状态.
这在逻辑上与绑定到C#(或任何.NET语言)中的实例方法的委托相同.
写这样的东西有三种方法.首先,您可以编写一个普通方法,然后将该方法的名称分配给委托变量.
void MyMethod() { Console.WriteLine("Hi!"); }
void Foo()
{
Action a = MyMethod;
a();
}
Run Code Online (Sandbox Code Playgroud)
其次,您可以使用C#2.0中引入的匿名方法语法:
void Foo()
{
Action a = delegate { Console.WriteLine("Hi!"); }
a();
}
Run Code Online (Sandbox Code Playgroud)
第三,您可以使用C#3.0中引入的lambda语法:
void Foo()
{
Action a = () => Console.WriteLine("Hi!");
a();
}
Run Code Online (Sandbox Code Playgroud)
最后两个的优点是方法的主体可以在包含方法中读取和写入局部变量.
lambda语法优于anon方法的优点是它更简洁,并且它对参数进行类型推断.
更新: anon-methods(delegate关键字)优于lambdas 的优点是,如果您不需要它们,您可以完全省略参数:
// correct way using lambda
button.Click += (sender, eventArgs) => MessageBox.Show("Clicked!");
// compile error - wrong number of arguments
button.Click += () => MessageBox.Show("Clicked!");
// anon method, omitting arguments, works fine
button.Click += delegate { MessageBox.Show("Clicked!"); };
Run Code Online (Sandbox Code Playgroud)
我只知道一个值得了解的情况,即在初始化事件时,您不必null在触发之前检查:
event EventHandler Birthday = delegate { };
Run Code Online (Sandbox Code Playgroud)
在其他地方避免了很多废话.
最后,你提到有四种仿函数.事实上,有一些无限可能的委托类型,虽然有些作者可能有他们的最爱,显然会有一些共同的模式.一个Action或Command不带参数和返回void,谓词采用某种类型的实例并返回true或false.
在C#3.0中,您可以使用您喜欢的任何类型的最多四个参数来创建一个委托:
Func<string, int, double> f; // takes a string and an in, returns a double
Run Code Online (Sandbox Code Playgroud)
回复:更新问题
你问(我认为)是否有很多用于lambdas的用例.有超过可能列出的!
您最常见的是在序列上运行的较大表达式(即时计算列表)中间.假设我有一份人员名单,我想要一份四十岁的人员名单:
var exactlyForty = people.Where(person => person.Age == 40);
Run Code Online (Sandbox Code Playgroud)
该Where方法是IEnumerable<T>接口上的扩展方法,T在这种情况下是某种Person类.
这在.NET中称为"Linq to Objects",但在其他地方称为序列或流上的纯函数式编程或"惰性"列表(同一事物的所有不同名称).
在.NET术语中,我认为你所描述的是Delegate- 它存在于所有的.NET中,而不仅仅是C#.
我不确定"闭包"是否会与比较器/谓词/变换器中的"类型"相同,因为在C#术语中,闭包只是一个实现细节,但可以是这三个中的任何一个.
在.NET中,委托以两种主要方式使用:
第一个很重要,但听起来你对第二个更感兴趣.实际上,它们的运行方式与单方法接口非常相似......考虑:
List<int> vals = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
List<int> evenVals = vals.FindAll(i => i % 2 == 0); // predicate
List<string> valsAsStrings = vals.ConvertAll(i => i.ToString()); // transformer
// sort descending
vals.Sort((x, y) => y.CompareTo(x)); // comparer
Run Code Online (Sandbox Code Playgroud)
在我们将代理外部的额外范围带入委托时,闭包更多:
int max = int.Parse(Console.ReadLine()); // perhaps 6
List<int> limited = vals.FindAll(i => i <= max);
Run Code Online (Sandbox Code Playgroud)
这里max将作为闭包捕获到委托中.
重新说明"框架内的课程是否为此做好了准备?" - 很多都是,而且LINQ还有很长的路要走这么做.LINQ提供了(例如)所有的扩展方法IEnumerable<T>- 这意味着没有基于委托的访问的集合可以免费获取它们:
int[] data = { 1,2,3,4,5,6,7,8,9 };
var oddData = data.Where( i => i % 2 == 1 );
var descending = data.OrderBy(i => -i);
var asStrings = data.Select(i => i.ToString());
Run Code Online (Sandbox Code Playgroud)
这里Where和OrderBy方法是LINQ扩展方法,它们接受委托.