2007年10月26日

C#3.0:Func デリゲート

   このエントリーをはてなブックマークに追加 Clip to Evernote
System名前空間に Func という味気ない名前のデリゲートがある。

public delegate TResult Func<TResult> ()
public delegate TResult Func<T, TResult>(T arg);
public delegate TResult Func<T1, T2, TResult> (T1 arg1,T2 arg2);
public delegate TResult Func<T1, T2, T3, TResult> (T1 arg1,T2 arg2,T3 arg3);
public delegate TResult Func<T1, T2, T3, T4, TResult> (T1 arg1,T2 arg2,T3 arg3,T4 arg4);

C#3.0では、このデリゲートの存在を知っていると何かと都合が良いらしい。
System.Linq 名前空間に定義されているメソッドも、このデリゲートを利用している。

このデリゲートは、引数を Tx型を受け取って、 TResult型を返すメソッドの定義なわけだが、
ちょっとこの使い方を試してみた。
C#1.1風に書くと、こんな感じだ。(もちろんC#1.1では、Genericが使えないので、コンパイルエラーになるが...)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication4 {
class Program {
static void Main(string[] args) {
ItemList<OrderDetail> details = GetDetails();

Func<OrderDetail, int> func = new Func<OrderDetail,int>(Foo);
int totalCount = details.Sum(func);
Console.WriteLine(totalCount);
}

static int Foo(OrderDetail detail) {
return detail.UnitCount;
}

static ItemList<OrderDetail> GetDetails() {
ItemList<OrderDetail> details = new ItemList<OrderDetail>();
details.Add(new OrderDetail(10, 50));
details.Add(new OrderDetail(5, 100));
return details;
}
}
class ItemList<T> : List<T> {
public int Sum(Func<T, int> selector) {
int sum = 0;
foreach (T item in this)
sum += selector(item);
return sum;
}

public double Sum(Func<T, double> selector) {
double sum = 0;
foreach ( T item in this )
sum += selector(item);
return sum;
}
}
class OrderDetail {
public int UnitCount;
public double UnitPrice;
public OrderDetail (int unitCount,double unitPrice) {
UnitPrice = unitPrice;
UnitCount = unitCount;
}
}
}

肝になるのは、Sumメソッドで、ここで、Funcを使っている。
何かの合計を求めるのだが、その「何か」を delegateとして外出ししてしまい、利用する側に指定させるというものだ。

以下の部分が、その利用する側の主要部分。

  Func<OrderDetail, int> func = new Func<OrderDetail,int>(Foo);
 int totalCount = details.Sum(func);

static int Foo(OrderDetail detail) {
return detail.UnitCount;
}


この部分を、順に C#3.0のやり方に書き換えていくと、

C#2.0の匿名メソッドを利用
  int totalCount = details.Sum(delegate(OrderDetail d) { return d.UnitCount; });

C#3.0のラムダ式を利用 (冗長版)
  int totalCount = details.Sum((OrderDetail d) => { return d.UnitCount; });

C#3.0のラムダ式を利用 (簡易版)
  int totalCount = details.Sum(d => d.UnitCount);

随分とすっきりした。

double totalUnits = details.Sum(d => d.UnitPrice * d.UnitCount);

といった使い方もできる。


この記事へのコメント
ただいま人気ブログを応援しています!
応援ポチッ!
Posted by アシタカ at 2007年10月27日 21:39
 

この記事へのトラックバックURL

http://trackback.blogsys.jp/livedoor/gushwell/51216239