ページ

2010-06-29

Windows Scripting

ちょっとばかり故あって、Windowsのスクリプト書きの手伝いに駆り出されました。以前にスクリプトを書いた時(その時はJScriptがメイン)の参照サイトを多数ブックマークしてあったのですが、片っぱし消滅してしまっています。WSHのヘルプファイルは結構読みでがあったのですが。ひょっとして、さっさとPowerShellに移行しろというMSの陰謀かもしれません。それでもVBScript系の参照先は結構見つかりました。記念にリンクを貼り付けておきます。

さしあたってはこのあたりを読んで、使い方を思い出しています。

2010-06-15

C#勉強中 C# 3.0 入門 8

C# 3.0 入門の続き
  • 第8回 LINQメソッド形式編
    予約語のエスケープ
    LINQ式で、というかC#の拡張機能において、拡張機能で使われるキーワードは、その拡張機能の構文(ここではLINQ式)内でのみ特別の意味を持つようになっているそうです。将来の拡張を考えると、予約語を増やさないこのような仕様は良いものです。しかし副作用として、他の部分で宣言された識別子が、拡張構文の中でキーワードと衝突してコンパイルエラーになってしまうことがあります。ここででは、通常の構文内で宣言された属性名のfrom等が、LINQ構文内ではLINQキーワードのfromなんかと衝突することによるコンパイルエラーになる例が挙げられています。これはある意味、後出しの拡張構文がある限り避けようの無い問題です。いままでの言語でも他の言語に移植しようとして予約語との衝突で大修正を行なうはめになるのはよくあることです。C#ではこのような問題を解消するために、’@’による識別子のエスケープ機能が用意されていて、拡張構文のキーワードと衝突する場合には識別子の頭に’@’を付けることによってキーワードとしてではなく通常の識別子として参照することができるようになってます。
    メソッド形式のLINQ
    実際のところLINQ式はシンタックスシュガー(SQL風というとこでしょう)であって、実態はIEnumerableに対する拡張メソッドとして定義されている、ということです。とりあえず、ここで例示されているのは、要素を加工するSelectメソッド、条件付きの選択を行なうためのWhereメソッドの二つ。残りはおいおい紹介されていくでしょう。
    メソッド形式でのみ可能なクエリ
    LINQ拡張機能の本体は拡張メソッドで、LINQ式はそれに対するシンタックスシュガーになっているわけですが、シンタックスシュガーが存在してない拡張メソッドもあるようです。ここではReverseメソッドが挙げられています。そういえば、SQLには単純なReverseって無いですね。
    メソッド形式のソート
    LINQ式で複数のorderby句を連結してソートを行なうようなケースでは、最初のorderby句はOrderByAscending/Descendingメソッドに、後続のorderby句はThenByAscending/Descendingメソッドに対応します。OrderByの方は全体のソートに対応していますが、ThenByの方は(先行するOrderByによって)順序付けられたIEnumerableに対応したメソッドになっています。OrderByメソッドを連結した場合には、どれもIEnumerable全体をソートしてしまうため、最後のOrderByだけが有効になってしまいます。ThenByの実装がどうなっているのかはかなり興味のあるところですね(遅延実行によって実装されているようです)。なお、解説ではOrderBy/ThenByメソッドにIComparerオブジェクトを渡す例が、メソッド使用時ならではの機能として挙げられていますが、orderby句でも関数呼び出しを記述することができるわけで、それほど特異な機能とは思えません。ただIComparerは列挙対象のオブジェクトの標準的な順序付けのために定義されることが多いので、それを使い回すという意味では有り難いかも知れません。
    メソッド形式の複数のソースからクエリする
    メソッド形式の場合、from句に直接対応するものは無く、列挙対象のIEnumerableオブジェクトに対してメソッドを並べていく形になります。ここで問題になるのが、複数のfrom句を持った、すなわち複数のソースに対するqueryの表現方法になります。メソッド形式では列挙対象にメソッドを適用していく形態になりますので、複数のデータソースを参照するためには特別な方法が必要になります。このために用意されたメソッドがSelectManyで、列挙の要素それぞれに対して他の列挙要素を組み合わせたシーケンスを生成(実際には遅延実行)します。結果として複数の列挙の直積が生成されることになります。パラメタとしてもうひとつの列挙を示すdelegateと二つの要素に対する加工の仕方を示す(selectに相当する)delegateとを渡します。確かに直感的にはないですが、それなりに理解できる構文です。
    メソッド形式のクエリの接続
    ここで挙げられているのはLINQ式でのselect~intoによるqueryの接続の話です。メソッド形式の場合には式の値自体がqueryの対象になるので、into句(途中のquery結果の保持)自体が不要になります。単純にSelect、Whereメソッドを連結していくだけで済みます。解説でも記述されていますが、メソッド形式の方がプログラミング的にはシンプルに記述可能なような気がします(逆にSQL文の方が普段のプログラミング的な記述からは乖離していると言えるかも知れません)。
    クエリ結果のグループ化
    これは簡単で from x in s group x by x.key が s.GroupBy((x) => x.key) というメソッドに置き換わるだけです。結果の列挙は x.key、xの二重の列挙になります。
    join句による結合
    join句はJoinメソッド、およびGroupJoinメソッドに展開されます。以前にまとめたテーブルにメソッド形式への展開方法を補足しておきます。
    内部結合 LINQ式 from x in s1
    join y in s2 on x.key equals y.key
    select new {Name = x.Name, Value = y.Value }
    メソッド形式 s1.Join(
    s2, (x) => x.key, (y) => y.key,
    (x,y) => new {Name = x.Name, Value = y.Value })
    グループ結合 LINQ式 from x in s1
    join y in s2 on x.Key equals y.Key into s3
    select new {Name = x.Name, Values = s3 }
    メソッド形式 s1.GroupJoin(
    s2, (x) => x.Key, (y) => y.Key,
    (x, s3) => new { Name = x.Name, Values = s3 })
    左外部結合 LINQ式 from x in s1
    join y in s2 on x.Key equals y.Key into s3
    from z in s3.DefaultIfEmpty(Default)
    select new {Name = x.Name, Value = z }
    メソッド形式 s1.GroupJoin(
    s2, (x) => x.Key, (y) => y.Key,
    (x, s3) => new { Name = x.Name, Values = s3.DefaultIfEmpty(Default) })
    .SelectMany(
    (x) => x.Values,
    (x, z) => new { Name = x.Name, Value = z } )
    メソッド形式ではLINQ式のjoinだけでなく、最後のselect句の部分まで、Join、GroupJoinのパラメタとして渡す形式になります。
    メソッド形式のlet句
    let句はLINQで複数ソースからの抽出を行なう場合に、先行するソースについての処理結果を(一時的に)保持しておいて、複数のソースの直積に対する演算を省略するために使われていました。しかし、メソッド形式の場合には、結果が常に列挙になるので、Selectメソッドでの演算結果はそのまま後続の(ソースに対する)SelectManyの対象になります。これは結局のところLINQ式でのlet句そのものであり、メソッド形式ではlet句は不要になっています。
    効率的に列挙可能にするという問題
    と、今まで扱ってきたのは、ローカルなIEnumerableオブジェクトについてのアクセスでした。これは対象のデータがローカルに保持されていることが前提になります。データがリモートに存在している場合(DBアクセスするような場合)にはこれは使用できません(一度内部に取り込めば別ですが)。そのようなケースは、次回の話題の専用のLINQプロバイダを使用することになります。
    DBのデータを扱う場合でも、固定的なデータであればローカルにキャッシュして性能を上げることができます。そのような場合に、DB上のvolatileなデータもキャッシュする固定的なデータも同一ロジックでハンドリングできるあたり、LINQのありがたみがあるのではないかと思っています。
全く以て知らなかったのですが、C#アーキテクトって、Turbo Pascal、Delphiの人だったのですね。道理で使い勝手の良い言語になっているわけですな(私、実はModulaファンで、TP、Delphiも割とお気に入り)。

2010-06-08

C#勉強中 C# 3.0 入門 7

C# 3.0 入門の続き
  • 第7回 LINQ応用編
    応用編の最初はLINQ式のデバッグの話。LINQ式に限りませんが、複雑な機能を実現するような文はどれでもデバッグが大変になります。結合を使いまくったSQL文なんかもトラブった時には目も当てられません(ので複雑なSQL文はなるべく避けるようにしています)。ただここに記載されているようにLINQ式の場合、式全体、where句、select句のそれぞれのレベルでブレークポイントを設定できるので、障害解析は随分と楽になっています。
    次の話題は前章で予告していたjoinの使い方色々。機能的はSQLでおなじみの機能で、グループ化結合、左外部結合が挙げられています。後々の参考のために、それぞれのjoin句の形式をまとめておきましょう。
    内部結合 from x in s1
    join y in s2 on x.key equals y.key
    select new {Name = x.Name, Value = y.Value }
    グループ結合 from x in s1
    join y in s2 on x.Key equals y.Key into s3
    select new {Name = x.Name, Values = s3 }
    左外部結合 from x in s1
    join y in s2 on x.Key equals y.Key into s3
    from z in s3.DefaultIfEmpty(Default)
    select new {Name = x.Name, Value = z }
    DefaultIfEmptyは列挙の対象が空だった場合にデフォルト値を割りつけるための関数で列挙データを扱う時に何かと役に立ちますね。
    次の話題はlet句。LINQの列挙の結果(途中)を保持する識別子を作成する機能のようです。ここで例に挙がっているケースでは、複数のfrom句の途中で一旦列挙(に対する計算結果)を保持して、最後のselect句で参照しています。複数のfrom句を使うと、それらの列挙の直積に対してselectが実行されるため、計算負荷が増大することがあります。一部のfrom句に対してlet句で処理を実行し、その結果を保持することによって計算負荷を軽減しています。このようなケースはままありますので、負荷軽減の手法として覚えておくのもいいかと思います。
    次の話題はquery式のインスタンス化。Query式を括弧で括ってインスタンスとして取り扱う技法です。インスタンス化して、インスタンスメソッドを呼び出すことによって、列挙に対する標準的な操作を行なうことができるようになります。ここでは、ToArrayによる(列挙の)配列化、Countによる個数のカウント、存在チェックのAny、が例として挙げられているます。ただ、query式のインスタンス化は式を一旦列挙の変数で受け取って、その変数をインスタンスとして扱っても同じ結果になります。文字列の生成の例では、
    static void Main(string[] args)
        {
            IEnumerable<char> q = from n in Enumerable.Range('A', 26)
                                  where (n % 2) == 0
                                   select (char)n;
            string s = new string(q.ToArray());
            Console.WriteLine(s); // 出力:DFHJLNPRTVXZ
        }
    でも同じ結果が得られます。そういう意味ではある種の省略記法に過ぎないのかも知れません。
    LINQには、このような式としての記述の他にメソッド表記なるものがあるそうで、次回はその説明になるようです。

Javaと.NET

@ITの記事から「Javaから見た.NET」。Javaと.NETの比較の話です。私も一応両方使うので、この手の比較は気になるところです。私の感覚からすると両方とも同じようなものとみなしてます。ただWebアプリ開発についてはJavaはフレームワーク多すぎ。.NETでも新しいフレームワークが出てきているので将来的には同じような混沌に陥るかもしれません。このような競合するものがあることによって、相互に影響し合っているようです。プリミティブからオブジェクトへの自動変換ってC#の独自機能かと思っていましたが、Javaにも(5.0で)導入されているのですね。独占状態にあると進歩が止まってしまいますから、ライバルの存在は大切でしょう。

2010-06-04

C#勉強中 C# 3.0 入門 6

おもいっきり間が空いてしまいましたが、C# 3.0 入門の続きを
  • 第6回 LINQ基礎編
    まずは、LINQの概要説明。確かにDBアクセスに絡んで解説されることが多いLINQですが、ここに記述されているように、言語仕様に組み込まれた集合演算と捉えるべきでしょう。DBのカラム名を間違えていて何度も実行時にエラーを出した身としては、IDEレベルでチェックが入るようになっている点だけでも有難いことです。しかし本質的には、DBとは独立してIEnumerableオブジェクトを対象とした集合演算です。DB、特にRDBの場合そのままではプログラム側のオブジェクト表現と親和性が良くないので、内部的にオブジェクト表現に変換するようなコードを愛用していた身としては、オブジェクトに対する集合演算が可能になったというのは何よりです。
    注意すべき点はLINQ式はコレクションを生成するのではなく、列挙オブジェクト(インターフェース)を生成している点で、これにより、データソースへのアクセスはLINQ式を受けた変数にアクセスした時点まで遅延されます。アクセス以前にデータソースを変更した場合には、その変更を含めたコレクションが列挙されます。またコレクションの複製を作らないのでメモリも無駄に使わずにすみます。このあたり、foreachでの列挙と異なる点で注意が必要になります。
    LINQの基本形は「from A in B where 条件 select 操作」となります。「from A in B」がfrom句で、(列挙可能な)データソースBのデータを名前Aで参照することを指示します。from句は複数指定可能で、それらの直積が列挙されます。列挙の条件はwhere句で限定することができます。列挙されたデータ(名前はfrom句で指定)はselect句で加工します。select句で単純にfrom句で指示した名前だけを指定した場合には、列挙されたデータそのものに対する列挙オブジェクトが得られますし、A.ToString()とすれば文字列の列挙オブジェクトが得られます。
    select句による加工で一番興味深いものは、「new { x.属性1, x.属性2 };」という形式での匿名型オブジェクトの生成でしょう。多数の属性を持つオブジェクトから一部の属性値だけを抽出し、それらの一部属性だけを持った(匿名の)オブジェクトを列挙することが可能になっています。この場合、型が匿名ですので、LINQ式の値はvar型の変数で受け取ることになります。
    「order by によるソート」はSQLでおなじみのものですね。「into句によるqueryの接続」はSQLでは見ないパターンですね。SQLではintoで一時テーブルに格納するようなイメージですがLINQでは受け皿の変数への格納イメージになるようです。「group 要素 by キー」はグループ化でこれもSQLでおなじみのものですが、LINQでは結果が「IGrouping」型で返されるようです。まあこれは決まりということで。
    join句による内部結合「join 名前 in データソース on 式1 equals 式2」もSQLでおなじみですが、まあ表現が少々異なっていますね。二つのfrom句で二つのデータソースから列挙するとそれぞれのでーたの直積になるので、データ数が多い場合には負荷が増大していきますが、joinでは参照が最小に抑えられます。join句には他の使い方もあるそうですが、そこらあたりは以降の章で、だそうです。