你希望能够同时对整个对象集合执行多种操作,并在功能上隔离这些操作。
使用函数对象(functor或function object)作为转换集合的工具。函数对象是任何一个可以作为函数被调用的对象。例如,委托
函数、函数指针,甚至是C/C++中定义了operator()的对象。
在软件中,经常需要对一个集合执行多种操作。假定你的股票组合包含了一系列股票。StockPortfolio类包含一个Stock对象的List,并且能够添加股票。
public class StockPortfolio : IEnumerable
{
List _stocks;
public StockPortfolio()
{
_stocks = new List();
}
public void Add(string ticker, double gainLoss)
{
_stocks.Add(new Stock()
{
Ticker = ticker,
GainLoss = gainLoss
});
}
public IEnumerable GetWorstPerformers(int topNumber) => _stocks.OrderBy((Stock stock) => stock.GainLoss).Take(topNumber);
public void SellStocks(IEnumerable stocks)
{
foreach (Stock s in stocks)
_stocks.Remove(s);
}
public void PrintPortfolio(string title)
{
Console.WriteLine(title);
_stocks.DisplayStocks();
}
#region IEnumerable Members
public IEnumerator GetEnumerator() => _stocks.GetEnumerator();
#endregion
#region IEnumerable Members
IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
#endregion
}
Stock类相当简单。只需要一个股票代码及其利润或亏损百分比。
public class Stock
{
public double GainLoss { get; set; }
public string Ticker { get; set; }
}
要使用这个StockPortfolio,可以向其中添加几支带利润/亏损百分比的股票,并输出初始股票组合。有了这个股票组合,你希望得到三支表现最差股票的列表,以便可以通过卖出股票来改进股票组合,然后再次输出它。
StockPortfolio tech = new StockPortfolio() {
{ "OU81", -10.5 },
{ "C#6VR", 2.0 },
{ "PCKD", 12.3 },
{ "BTML", 0.5 },
{ "NOVB", -35.2 },
{ "MGDCD", 15.7 },
{ "GNRCS", 4.0 },
{ "FNCTR", 9.16 },
{ "LMBDA", 9.12 },
{ "PCLS", 6.11 } };
tech.PrintPortfolio("Starting Portfolio");
// 出售表现最差的3支股票
var worstPerformers = tech.GetWorstPerformers(3);
Console.WriteLine("Selling the worst performers:");
worstPerformers.DisplayStocks();
tech.SellStocks(worstPerformers);
tech.PrintPortfolio("After Selling Worst 3 Performers");
迄今为止,没有发生任何特别令人感兴趣的事情。通过查看GetWorstPerformers方法的内部代码,看一下如何查看三支最差的股票。
public IEnumerable
首先通过调用IEnumerable
GetWorstPerformeers返回一个IEnumerable
public void SellStocks(IEnumerable stocks)
{
foreach (Stock s in stocks)
_stocks.Remove(s);
}
函数对象具有几种不同的样式:生成器(不带参数的函数)、一元函数(带一个参数的函数)和二元函数(带两个参数的函数)。如果函数对象恰好返回一个布尔值,那么它就有一个更为特定的命名约定:返回布尔值的一元函数称为谓词;返回布尔值的二元函数称为二元谓词。在Framework 中包含了Predicate
List
最初以函数对象的方式来思考会有一些挑战,但是一旦花点时间研究它,就会开始看到它带来的强大可能性。任何能够编写一次、调试一次,然后多次使用的代码都是有价值的,函数对象能帮助你达到这一点。
上述示例的输出如下所示。
Starting Portfolio
(OU81) lost 10.5%
(C#6VR) gained 2%
(PCKD) gained 12.3%
(BTML) gained 0.5%
(NOVB) lost 35.2%
(MGDCD) gained 15.7%
(GNRCS) gained 4%
(FNCTR) gained 9.16%
(LMBDA) gained 9.12%
(PCLS) gained 6.11%
Selling the worst performers:
(NOVB) lost 35.2%
(OU81) lost 10.5%
(BTML) gained 0.5%
After Selling Worst 3 Performers
(C#6VR) gained 2%
(PCKD) gained 12.3%
(MGDCD) gained 15.7%
(GNRCS) gained 4%
(FNCTR) gained 9.16%
(LMBDA) gained 9.12%
(PCLS) gained 6.11%
MSDN 文档中的“System.Collections.Generic.List