ページ

2010-03-21

C#勉強中 C# 3.0入門 2-5

間が空きましたが C# 3.0入門の続きをば
  • 第2回 ラムダ式と型推論
    最初の節はラムダ式そのものよりも、Attribute(Reflection)の効率的な使用法だと思えます。ここではラムダ式、delegateを使うことにより、Reflectionの参照を最小限に抑えている点の方が役に立っています。まあ、ラムダ式の使い方の一種ではあるのでしょうね。
    次の節の前半はシステム規定のdelegateの型。ActionとPredicateは良く使いそうです(というか、このレベルのdelegateを自前で定義しないよいうに注意しないといけませんね)。Funcシリーズはちょっと微妙。頭に記載されているように、汎用過ぎて正当性のチェックとかが無意味になってしまう可能性が出てきます。このレベルになると自前で宣言した方が可視性が上がるように思えますね。後半はラムダ式での型推論の話。確かに型推論で記述量が減るのは認めますが、こういうシステムの入り組んだ処理に頼って記述を減らすのはどうかと思いますね。良く言われる例ですが、演算子の優先順位に頼らず、無駄に括弧を付けた方が良い、というのを思い出します。まあ、単純/明快な推論でカバーできるならともかく、ここの最後の例なんかはあまり嬉しく無いでしょう。ちなみに個人的にはエレガントとというよりは悪趣味の世界に入り込んでいると思いますね。
    前節の後ろから次節の前半で、やっと本質的なdelegateとlambdaの違いが出てきました。本質的にはdelegateは匿名(無名)関数、lambdaは式ツリー(Expression Tree)なのですね。ただ、式ツリーをdelegateの式(関数)としても使用可能だということのようです。式ツリーはコンパイル時に生成されるものなので、コードの中で動的に変更可能な式を作成する手段が提供されることになります。通常のコードではこのような機能が使いません。しかし次回予告にあるようにLINQがこれを使って実現されているようで、たしかに検索の条件を実行コードに落とすようなケースでは必要になりそうです。
  • 第3回 varによる変数宣言とコレクション初期化子
    ちなみに私、個人的には「過剰な否定」派であること明記しておきます。LLでなんども意図しない型変換で泣いておりますので。でまずは、コンパイル時に型が確定するのでひと安心です。これも型推論に基づく省略記法に過ぎないのでしょうか?たしかにオブジェクトをnewして変数に格納するときの冗長性は腹がたちますので、これが簡略化されるのは悪いことではありません(このケースでは型推論と言っても明確そのものです)。ただ型推論が難しくなるようなケース(次節の配列問題とか)ではやはり避けたいところです。
    最後の節はコレクション初期化子の話題で、C#ではコレクションに対する初期化子の記述が可能になったというものです。前に触った時だと、perlでは不可、pythonでは可能だったように記憶しています。でコレクションの初期化を使いたいばかりにpythonで書いたりしましたが。便利になった、と思ったら単なるシンタックスシュガーとのこと。ちょっとがっかりですが、ソースは見た目、ということでOKとしましょう。Dictionaryにも初期化設定が可能になっているのは有り難いですね。
  • 第4回 自動実装と自動定義
    自動実装プロパティって便利なのでしょうか?よく使うパターンでは、内部的には自由なアクセスを、外部からは特定のメソッドによるアクセスのみを提供しますが、内部からでもプロパティ経由でしかアクセスできないという点で引いてしまいます。確かに一部の(オブジェクト指向をどう誤解したんだよという)アクセッサ至上主義の人達には愛用されそうですが。単純なデータ保持のためのクラスと言ったものの場合には便利になるのかもしれません。そういえば、この手のデータ保持のためのクラスみたいなものも無いわけではありませんからね。
    と、次の節ではまさにデータを保持するためだけの匿名型が出てきました。初期化のみ可能な読み出し専用のプロパティを持ったクラスです。型チェック云々を気にしなければDictionaryででも実装できそうなデータオブジェクトです。ただ、C#では、初期化子の識別名と初期化値に基づく型が推定されるようで、コンパイル時に型チェックの対象となる点でしっかりした型(オブジェクト)になっています。で、何に使うかといえば、LINQのselectの結果を保持するため、といいきってもいいかと。同様に、データ項目が動的に変化するような処理結果を保持するデータ型として使えるでしょう(古い言語ではKey/Valueペアの集合で表現していたようなものです)。
    最後の節は、オブジェクト初期化子の話。匿名型はオブジェクト初期化子からの型推論によって自動的に(名無しの)型(オブジェクト)を生成していたわけで、初期化子自体は任意のオブジェクトの初期化に使えます。ここではオブジェクトの初期化の順序/制限について解説しています。宣言→コンストラクタ→初期化子という順番はまあ期待通りなので何も問題はありません。問題になるのは、初期化子ではprivate/readonlyフィールドへの設定ができないという点でしょう。確かに仕組みでいえば当然なのですが、あるクラスで固定的なデータを用意するような場合にはオブジェクト初期化子による生成ができない点は残念です。概念的にはオブジェクトの初期化と考えるよりも構造体の初期化に近いイメージで捉えた方が良さそうです。
  • 第5回 拡張メソッド
    普通にクラスで定義するメソッドでも、インスタンスメソッドとして定義したもの「obj.method()」と、自オブジェクトをパラメタとして渡すクラスメソッド「method(obj)」とを用意することがあります。内部データにアクセスしないのであればクラスメソッドは外部で定義しても構いません。拡張メソッドは、このような外部で定義された(オブジェクトインスタンスをパラメタとする)メソッドを、クラスメソッドと同じ形式で呼び出すことができるようにした、ある種のシンタックスシュガーのようです。まあ、既存クラスに対するある種の拡張システムと考えればいいのでしょう。
この後は.NET 3.5の花形、LINQの解説になりますので、今日のところはここまでにしておきます。

2010-03-16

C#勉強中 C# 3.0入門 1

C# 3.0入門読み始め。やっとVS2008に追い付いてきました。また直ぐに追い越されるのですが。
  • 第1回 ラムダ式
    この章は、ラムダ式へのイントロですね。本質的にはdelegateの省略記法と考えていいかと思います。確かにソート時の比較や、Find等の条件としては便利でしょう。ただ、どのレベルでdelegate、lambdaを使い分けるかは結構面倒そうな気がします。
次の章はラムダ式の型推論、結構重そうなところなので、今日はここで切り上げておきます。

2010-03-12

C#勉強中 C# 2.0入門 6-最終回

  • 第6回 部分クラスと静的クラス
    最初の節はdelegateによる変数のキャプチャの話。delegateによるキャプチャが生成されると、delegateが生きている限り変数(オブジェクト)も生き続けるので、Garbage Collectionされないという注意。いわれてみればもっともな話ですが、見逃しやすい点です。Javaでもそうでしたが、オブジェクトのメモリがどのようなタイミングで回収されるかをイメージするのはそれなりに重要かと思います。ただ長時間動作し続けるアプリケーションでなければ気にすることも無いでしょう。
    部分クラスは便利ですね。クラスのコードが巨大化して保守し難くなることがありますし、すべてのコードが密に結合しているわけでもありません。場合によっては、部分クラスによってファイル分割するのも便利でしょう。
    静的クラスも、なぜ他の言語に無いのか不思議になる機能ですね。Singleton Patternなんぞと銘打つぐらいなら最初からこういうクラスを用意しておけばいいのに。まあ、ある種の後知恵なのかもしれません。アクセッサの拡張(アクセシビリティ制御)は、最近VSを使い始めた私からすると、おや、当初は無かったんだ、といった機能です。こうやってみると、初期のC#(VBもでしょうね)では、いまや普通に使うような機能が結構漏れていたのですね。
  • 第7回 名前空間のエイリアス修飾子と外部アセンブリ
    List3でエラーになる理由が最初わかりませんでした。名前空間はグローバルな名前空間から識別名毎にネストした構成になっていて、ある識別名への参照は、ローカルな名前空間から始まって、(個別の識別名が)最初に一致したところから、再度下位の空間を探索していくという仕様になっているのですね。で、List3の場合、A.B.C.SayHelloは、最初はSample.Main空間で探索して見つからないので、次に、その上位のSample名前空間で探索されます。すると、Sample空間に名前A(Sample.A)があるので、そこで、B.C.SayHelloを探すことになります。すると、B.Cまでは見つかりますが、そこにはSayHelloは無いのでエラーになるわけですね。じっくり考えるとごもっとも、ですが、これは間違え易そうです。ここではglobal::で参照先を明確化していますが、汎用的な解決方法としては次に節で説明されているextern aliasで指定するべきなのでしょう。
    InternalsVisibleToも使い勝手のよさそうな属性です。コード上、特定のクラスでしか使わないクラスは結構ありますので、無駄にパブリックにしない方法が提供されているのは有り難いですね。
  • 最終回 小さな改善とコンパイラの新機能、そして3.0への展望
    まあ、ここは読み飛ばしですね。確かにさっさとC#3.0の勉強に入らないと。
InternalsVisibleToの話題に関連して、NUnitの話が出てきています。後で勉強するためのリンクをメモしておきます。 
ただ、ざっと見た感想をいうと、ひとこと「なにか胡散臭い」、でした。せっかくオブジェクト指向言語使っていて、こういうテストしていのかな?オブジェクト指向言語の場合はオブジェクトレベルでの動作確認が簡単にできるのに、異なったレベルのテストで、わざわざ面倒にしているとしか思えません。

2010-03-11

C#勉強中 言語仕様の進化

delegateとclosureの違いを調べている時に偶然見つけたページですが
「C# 1.1からC# 3.0まで~言語仕様の進化」
(ほぼ)同じ処理が言語の進化に応じて、どのように表現が変わっていくかで示したものです。旧版にどのような問題点があったか、それが新版でどのように解消されるかが、実際のコードベースで記載されています。これは読み易いし、イメージが掴みやすいですね。

2010-03-10

C#勉強中 C# 2.0 入門 5

C# 2.0 入門続き
  • 第5回 匿名メソッドとデリゲート
    delegateそのものは判りやすいし、いかにも使い勝手が良さそうに思えます。難しくなるのはdelegateが定義された場所での上位スコープの変数への参照が許される点です(というか、これってクロージャ?)。このあたりの用語は結構言語毎に微妙に違うので判りにくいものがあります。要はdelegateにはコードそのものと、そのコードが参照するスコープ内の変数のセットが含まれるわけですが、変数の「何が」含まれるのかが問題になるわけですね。ここのサンプルコードによると、変数値ではなく、(動的に生成された)変数そのものが含まれる(束縛される)ようです。結果、for ループ内で制御変数(そのもの)を参照するdelegateを定義すると、すべてが同じ変数を含んでしまうため、最終的な制御変数値への参照になってしまうということでしょう。
今日はヘビーなところでしたので、これだけでした。

C#勉強中 ラムダ式

@ITの記事からラムダ式の話
delegate自体が他の言語で言うところのラムダ式だと思っていたのですが、delegateとは別にラムダ式があるのですね。実際にはdelegateに対するシンタックスシュガーのようです。使い分けが問題かな。Cでの三項演算子とif文の関係みたいなものかと考えています。ちょっとしたコードならラムダ式表現の方が見易くなるのは確かです。でもCで三項演算子嫌う人がいるように、ラムダ式を嫌う人がいそうです。

2010-03-09

C#勉強中 C# 2.0 入門 2-4

C# 2.0 入門続き
  • 第2回 ジェネリック
    最近になって.NET系を使い始めた私にとっては、最初期にはGenericが無かったことの方が驚きです。新しいオブジェクト指向言語でなら当然の機能だと思っていました。VBではいやというほどGeneric型を使っていたので、ここはC#での記法を学ぶだけで過ごしましょう。
  • 第3回 新しい繰り返しのスタイル - yield return文とForEachメソッド
    反復子?ここではRubyの例がでていますが、昔にちょっと触ったPythonにもありました。そういえば、Excelのセルアクセスでも使いましたね。使う方はごく簡単ですが、作成する方は面倒ですね。そういえば反復子のコード、何かのサンプルで見たことがありましたが、なにやら解りにくかった記憶があります。まあやりたい事は判るのですが通常のコードとは全く異なった動作になりますから。ここの説明を読んでやっと内容(というかこのコードがどのような実行パターンに展開されるか)が理解できました。最後の節で実際の展開イメージが記載されいます。これを見れば一目瞭然です。
    と、ここまで反復子の話を書いてきて最後にCollectionオブジェクトのForEachメソッドを挙げますか?しかも、yield returnはめったに使わないし、こちらの方が遥かに早いと。これはJavaなんかのMapと同系列の機能ですね。単純にコレクション内のすべてのデータについての処理を行なうなら、こちらの方が適していますね。
  • 第4回 Findメソッドとnull許容型
    前半はCollectionのFind、 FindAllメソッドの話題で、これは前章のForEachメソッドと同じ系列のものです。ForEachは要素に対してある演算を施していくのに対して、Find、FindAllは特定条件を満たす要素をピックアップしていくものです。これもいまや当たり前の機能です。
    で、後半はnull許容型の話題。たしかにSQL連携しているとやたらとnullが出てきて、それらが簡単に処理可能になるのは解ります。言語仕様的にはあればいいかなとは思いますが、システム設計的には私もNULL撲滅委員会にシンパシーを感じる方なので、めったに使わないかと思います(だいたいデフォルト値への代用で済みますからね)。
今日のところはここまで。