C# 函子我应该什么时候使用它们它们的预期用途是什么
我就是不能把我的头绕在他们身上 据我所知,它是动态地向类添加逻辑。框架内的类是否为此做好了准备 为什么我要扩展类并在扩展中添加功能呢。我将在全球范围内访问,并且更易于维护 我读过有4种函子类型: 比较器C# 函子我应该什么时候使用它们它们的预期用途是什么,c#,.net,generics,lambda,functor,C#,.net,Generics,Lambda,Functor,我就是不能把我的头绕在他们身上 据我所知,它是动态地向类添加逻辑。框架内的类是否为此做好了准备 为什么我要扩展类并在扩展中添加功能呢。我将在全球范围内访问,并且更易于维护 我读过有4种函子类型: 比较器 闭包 谓词 变压器 我们可能应该处理好每一个问题 p、 在vb中有类似的东西吗 所以我可以说,我认为lambda表达式是函子。这让我有点清醒:)(呵呵) Lambda表达式是函子吗 匿名函数是函子吗 但我问这个问题是因为我遇到了另一种类型的混蛋,即: delegate void Functo
闭包
谓词
变压器 我们可能应该处理好每一个问题 p、 在vb中有类似的东西吗 所以我可以说,我认为lambda表达式是函子。这让我有点清醒:)(呵呵)
- Lambda表达式是函子吗
- 匿名函数是函子吗
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;
}
}
因此,没有华丽的lambda风格的东西
现在我有了这个例子,但根本不清楚为什么这是一个“好”的解决方案
委托(函子)“在大多数情况下”是否用作lambda表达式或匿名方法,只是作为程序员的快捷方式?据我所知,只有少数情况下,它们实际上是解决问题的首选。在.NET术语中,我认为您所描述的是委托
——它存在于整个.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
这里的
,其中
和OrderBy
方法是接受委托的LINQ扩展方法。我确信您指的是Lambda表达式。这些都是可以快速编写的小函数,它们具有“=>”运算符的特征。这些是C#3.0的一个新特性
这个例子将是一个经典的变压器;要使用它,我们需要一个委托来定义Lambda函数的签名
delegate int Transformer(int i);
现在使用此委托声明Lambda:
int max = int.Parse(Console.ReadLine()); // perhaps 6
List<int> limited = vals.FindAll(i => i <= max);
Transformer sqr = x => x * x;
我们可以像使用普通函数一样使用它:
Console.WriteLine(sqr(3)); //9
这些在LINQ查询中经常使用,例如排序(比较器),搜索(谓词)
《C#Pocket Reference》一书(在我看来,除了是最好的一本书外,对Lambdas也有很好的了解。(ISBN 978-0-596-51922-3)术语很有趣;我对术语“函子”的自然解释是它引用了匿名方法。因此,这将是我对它的理解 以下是我的一些典型用途: 比较(通常用于对列表进行排序):
List ints=new List();
AddRange(新的int[]{9,5,7,4,3,5,3});
排序(新比较(委托(整数x,整数y)
{
返回x.CompareTo(y);
}));
//是的,我知道ints.Sort()会产生相同的结果,但是嘿,它只是
//概念代码示例;o)
//以及较短的.NET 3.5版本:
整数排序((x,y)=>
{
返回x.CompareTo(y);
});
我将使用这种方法进行比较,而不是在它自己的方法中使用该方法的委托,在这种情况下,这种特殊的排序只发生在一个地方。如果我可能想在其他地方使用相同的比较,那么它将使用自己的、可重用的方法
我的另一个相当常见的用途是在单元测试中,当测试依赖于引发的某个事件时。我发现,在Workflow Foundation中对工作流进行单元测试时,这一点至关重要:
WorkflowRuntime runtime = WorkflowHost.Runtime;
WorkflowInstance instance = runtime.CreateWorkflow(typeof(CreateFile));
EventHandler<WorkflowEventArgs> WorkflowIdledHandler = delegate(object sender, WorkflowEventArgs e)
{
// get the ICreateFileService instance from the runtime
ISomeWorkflowService service = WorkflowHost.Runtime.GetService<ISomeWorkflowService>();
// set the desired file content
service.DoSomeWork(instance.InstanceId, inputData);
};
// attach event handler
runtime.WorkflowIdled += WorkflowIdledHandler;
instance.Start();
// perform the test, and then detach the event handler
runtime.WorkflowIdled -= WorkflowIdledHandler;
WorkflowRuntime runtime=WorkflowHost.runtime;
WorkflowInstance实例=runtime.CreateWorkflow(typeof(CreateFile));
EventHandler WorkflowIdledHandler=委托(对象发送方,WorkflowEventArgs e)
{
//从运行时获取ICreateFileService实例
ISomeWorkflowService服务=WorkflowHost.Runtime.GetService();
//设置所需的文件内容
服务.DoSomeWork(instance.InstanceId,inputData);
};
//附加事件处理程序
runtime.WorkflowIdled+=WorkflowIdledHandler;
instance.Start();
//执行测试,然后分离事件处理程序
runtime.WorkflowIdled-=WorkflowIdledHandler;
在这种情况下,将事件处理程序声明为匿名方法更简单,因为它使用在单元测试方法范围中定义的实例
变量。如果我选择将事件处理程序作为它自己的独立方法来实现,我还需要找到一种方法让它获取实例
,可能是通过引入类级成员,这在单元测试类中似乎不是一个完美的设计
我在代码中发现这种情况的情况更多,但它们通常有一到两个共同点:
- 除了在那个特定的地方之外,我对从任何地方引用那个段代码都不感兴趣
- 该方法需要访问超出常规方法范围的数据
- 我认为你混淆了不同语言的术语。您似乎在C++或java感测中使用“函子”,例如。在C++中,它是一个重载函数调用运算符的类的对象,因此它可以用作函数,但可以使用状态。
这在逻辑上与C#(或任何.NET语言)中绑定到实例方法的委托相同
写这种东西有三种方法。首先,您可以编写一个普通方法,然后将该方法的名称指定给委托变量
void MyMethod() { Console.WriteLine("Hi!"); }
void Foo()
{
Action a = MyMethod;
a();
}
其次,可以使用C#2.0中引入的匿名方法语法:
第三,可以使用C#3.0中引入的lambda语法:
后两种方法的优点是
List<int> ints = new List<int>();
ints.AddRange(new int[] { 9, 5, 7, 4, 3, 5, 3 });
ints.Sort(new Comparison<int>(delegate(int x, int y)
{
return x.CompareTo(y);
}));
// yes I am aware the ints.Sort() would yield the same result, but hey, it's just
// a conceptual code sample ;o)
// and the shorter .NET 3.5 version:
ints.Sort((x, y) =>
{
return x.CompareTo(y);
});
WorkflowRuntime runtime = WorkflowHost.Runtime;
WorkflowInstance instance = runtime.CreateWorkflow(typeof(CreateFile));
EventHandler<WorkflowEventArgs> WorkflowIdledHandler = delegate(object sender, WorkflowEventArgs e)
{
// get the ICreateFileService instance from the runtime
ISomeWorkflowService service = WorkflowHost.Runtime.GetService<ISomeWorkflowService>();
// set the desired file content
service.DoSomeWork(instance.InstanceId, inputData);
};
// attach event handler
runtime.WorkflowIdled += WorkflowIdledHandler;
instance.Start();
// perform the test, and then detach the event handler
runtime.WorkflowIdled -= WorkflowIdledHandler;
void MyMethod() { Console.WriteLine("Hi!"); }
void Foo()
{
Action a = MyMethod;
a();
}
void Foo()
{
Action a = delegate { Console.WriteLine("Hi!"); }
a();
}
void Foo()
{
Action a = () => Console.WriteLine("Hi!");
a();
}
// 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!"); };
event EventHandler Birthday = delegate { };
Func<string, int, double> f; // takes a string and an in, returns a double
var exactlyForty = people.Where(person => person.Age == 40);