存在を忘れていたわけではない。
ただ単に書くネタがなかっただけ。
要するにWEBLOGってヤツに僕は向いていないのだと思う。
MIXIに書いた日記 → いい感じならBLOGへ、というスタイルが正解かな?

というわけでMIXIで書いた記事の再編集。

C# 3.5の仕様をいろいろごちゃごちゃ見てた。

なんだかPerlじみて来たな。とても自由に書けるけど・・・ゴニョゴニョ、ってやつ。
3項演算子とラムダ式の併用で、1行の処理量が異常になる。

例えば。ある自然数配列の要素を、偶数なら/2、奇数なら*2して総和を求めるということをすると。

c000: // C# 2.0 (without ternary operators):
c001: int[] nat2 = new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
c002: int sum2 = 0;
c003: foreach (int x in nat2)
c004: {
c005:  if (x % 2 == 0)
c006:   sum2 += x / 2;
c007:  else
c008:   sum2 += x * 2;
c009: }
c010: Console.WriteLine(sum2);
c011:
c012: // C# 3.0 (with a lambda expression and a ternary operator):
c013: var nat3 = new[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
c014: var sum3 = nat3.Sum(x => x % 2 == 0 ? x / 2 : x * 2);
c015: Console.WriteLine(sum3);

// result:

r001: 70
r002: 70

あんまり実用性のある例とは言えないけど、まあ分かりやすくて且つ大幅な削減が見込める例ってことで・・・。

一応特徴的なところを列挙すると・・・

c013から

var nat3

C#3.0からローカル変数のvar宣言による型推論というのが効く。
何でも入る型、って言うとobjectのBoxingの事だから違う。
それにvarは型じゃない。あくまで「宣言」だから、コンパイル時にちゃんと適切な型として用意される。

同じくc013から

new[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

配列の初期設定時には、型名の省略が可能。初期化子から適切な型が推論される。推論の詳細は検証してないけど・・・。

そしてc014から

nat3.Sum(x => x % 2 == 0 ? x / 2 : x * 2)

C#3.5から実装のLINQによれば、列挙可能オブジェクト(Enumerable)にSQLライクな処理ができる。Sumもその一つ。
ちなみに、Sumの実装は

c015: // decimal IEnumerable<T>.Sum(Func<T, decimal> selector);

となっている。ただし、これにはdecimal、decimal?、int、int?・・・といったたいていの値型数値と、そのNullable型クラスのオーバーロードがついている。

とここで、.NET Framework 3.5からの独自delegateが。

c016: // Func<T, decimal>

これは、.NET Frameworkから加わったdelegate。

c017: delegate TResult Func<T, TResult>(T a);
c018: delegate TResult Func<T, TResult>(T1 a1, T2 a2);

など、引数の数4つ(T1,…T4)まで対応したdelegateがあらかじめ用意されている。

そして最後。ラムダ式。
こいつがなかなか癖強いんだけど。
今までは匿名のdelegateといやあ

c019: // delegate (int x)
c020: // {
c021: //  return x * 2
c022: // }

みたいのを書いてたけど、これが

c023: // (int x) => { return x * 2; }

とゆーふーになる。=>はC#3.0から新しく用意された演算子。ラムダ表記のための演算子で、引数リストと式、あるいはステートメントを結びつける、きわめて左辺結合の強い演算子。
ちなみにc023は「ステートメント表記」のラムダ。このラムダを式で書くと

c024: // x => x * 2

となる。
このとき規則があって、
まずc023にある引数の(int x)のような型宣言は、型推論の対象となるため、一部例外はあるものの基本的に省略可能。だからたとえば

c025: Func
c026:  f1 = (int x) => { return x * 2; };

というのは、左辺のFuncから引数のintとstringが型推論できるために、

c026':   f1 = (x) => { return x * 2; };

と書ける。
加えて、ラムダ式の引数リストに引数が一つしかないときは、リストを囲む括弧がいらなくなる。つまりc026′はさらに省略できて、

c026'':   f1 = x => { return x * 2; };

んで、ステートメント表記から式表記に直すことでreturnが省略できて

c27: Func<int, int> f2 = x => x * 2;

・・・ってえいうんだけどさ・・・

俺はc000~c010の例とc012~c015の例、どちらが素晴らしいか、って聞かれたら間違いなく上、と答える。

ラムダ式は個人的に気持ち悪すぎて、数値計算には使いたくないな。
出来るだけdelegateの代用、ってレベルに止めたいな、と思う。
varも使いたくないなあ。
後々変数の型を変えなきゃ行けないなんて、コアな型でも無い限り、それははっきり言って設計ミスだろう。
設計の段階で見込まれる拡張は、クラスの設計で対応するべきだと思う。

そんな考え方も古い、ってことなのかなぁ。
とにかく、安易にvarだのlambdaだの、ternaryだの使ったソースが蔓延しそうで怖いな、と思うのでした。