Visual Studio 2008 C#で開発効率アップ!

第3回 コード比較で理解するC#3.0の新機能(3)

この記事を読むのに必要な時間:およそ 2.5 分

はじめに

前回は,ラムダ式についてをご説明しました。 今回は,いよいよC#3.0の新機能として有名なLINQについてをご説明したいと思います。

LINQ(Language Integrated Query)

C#3.0

var q = 
    from x in this.Collection
    where x.Age < 20
    orderby x.Name
    select new { Code = x.Code, Name = x.Name };

C#2.0

List<Item> q = new List<Item>();
foreach (Member x in this.Collection) {
    if (x.Age < 20) {
        Item item = new Item();
        item.Code = x.Code;
        item.Name = x.Name;
        q.Add(item);
    }
}
q.Sort(delegate(Item a, Item b) {
    return string.Compare(a.Name, b.Name); });

上記はthis.Collectionというコレクションのデータから,qという新しいコレクションを以下の規則に準じて生成しています。

  • 未成年(Ageプロパティの値が20未満)のアイテムのみ
  • 名前順に並べ替え
  • Code,Nameプロパティだけをメンバとしたオブジェクトに格納

C#2.0のコードでは,完全に行うべき手続きに対するプログラミングが必要であることに対して,C#3.0のコードではLINQを使うことで,1つのクエリー式を記述しているだけにすぎません。

また,Code,Nameプロパティだけのオブジェクトを作成するための記述は,匿名型によって簡単に実現できていますが,C#2.0では,以前ご説明した通り,別途Itemクラスを用意する必要があります。

どちらのサンプルコードも,以下のコードによって正しく格納できていることを確認できます。

foreach(var item in q) {
    Console.WriteLine(item.Code.ToString() + ":" item.Name);
}

LINQとは

LINQとは,言語統合型クエリ(Language Integrated Query)を略した名前です。 その名の示す通り,冒頭のC#3.0のサンプルコードを見ると,クエリー式がコードとして記述できています。

LINQでできること

LINQでは,クエリー式によるコーディングが可能であるため,DBMS(Database Management System)に関するテクノロジーだと誤解している方もいるようですが,これは大きな間違いです。冒頭のサンプルコードのように,コレクションオブジェクトに対しても使うことができます。

  • LINQ to Objects
  • LINQ to XML
  • LINQ to DataSets
  • LINQ to SQL
  • LINQ to Entities

上記を見ると,我々がプログラミングをする上で,LINQはフロントエンドとしての役割を持っており,バックエンドとしては,オブジェクト・XML・DBMSなどのさまざまなデータソースに対応できることがわかると思います。

なお,冒頭のサンプルコードはLINQ to Objectsになります。

LINQ to Objects

恐らくLINQ to Objectsは,皆さんがLINQに触れるきっかけとなる最も身近なものになるでしょう。

LINQ to Objectsは,IEnumerable,IEnumerable<T>インターフェイスを継承したオブジェクトにクエリー式を適用できます。 ですから,foreachを使ってオブジェクトに対して反復処理をさせる場面では,LINQの利用を検討してみてください。

例えば,次のコードはDataGridViewの左上のセルをカレントセルにするためのコードです。

var q =
    from DataGridViewColumn column in grid.Columns
    where column.Visible
    orderby column.DisplayIndex
    select p.Index;
if (q == null) return;
var columnLeftIndex = q.First();
grid.CurrentCell = grid[columnLeftIndex, 0];

grid.Columnsオブジェクトは,DataGridViewColumnCollection型なので,IEnumerable型を継承しています。

IEnumerable<T>のようにコレクションに格納されるデータ型が明確に指定されていないため,各要素の型が推論できません。 このため,from DataGridViewColumn column in grid.Columnsのようにcolumnオブジェクトの型を直前に明記しています。

LINQ to XML

XMLのXElementに対してクエリー式を適用できます。

LINQ to XMLを実行するためには,以下のようにSystem.Xml.Linq名前空間をusingする必要があります。

using System.Xml.Linq;

以下のコードは,http://blog.example.com/rssという架空のURLから取得したXML形式のRSSフィードデータを元に,タイトルの一覧を取得するためのサンプルです。

var d = XDocument.Load("http://blog.example.com/rss");
var q = 
    from x in d.Root.Element("channel").Elements("item")
    select x.Element("title").Value;

LINQ to DataSets

ADO.NETのDataSetに対してクエリー式を適用できます。

以下のコードは,MyDataSetのMyDataTableに格納されたデータから,未成年者の名前を取得するためのサンプルコードです。

using(var ds = new MyDataSet()) {
    using(var ad = new MyDataTableAdapter()) {
        ad.Fill(ds.MyDataTable);
    }
    var q =
        from x in ds.MyDataTable
        where x.Age < 20
        select x.Name;
}

LINQ to SQL

SQLサーバー上のデータベースに対してクエリー式を適用できます。

以下のコードは,ConnectionStringに指定された接続文字列に基づいてDataContextオブジェクトを作成したものから,未成年者の名前を取得するためのサンプルコードです。 MyDataContextクラスはLINQ to SQLクラスデザイナによって簡単に作成できるようになっています。

using (var db = new MyDataContext(ConnectionString)){
    var q =
        from x in db.MyDataTable
        where x.Age < 20
        select x.Name;
}

LINQ to Entities

ADO.NET Entity Frameworkから提供される概念エンティティ(例えば,複数のテーブルを1つのエンティティとするなど)に対してクエリー式を適用できます。

以下のコードは,contextオブジェクトのMyDataTableエンティティから,未成年者の名前を取得するためのサンプルコードです。

var q = 
    from x in context.MyDataTable
    where x.Age < 20
    select x.Name;
}

クエリー式の正体

クエリー式の正体は,シンタックスシュガーです。 従って,クエリー式を使わずに記述することもできます。

以下の2つのコードを見比べてみてください。

var q = 
    from x in this.Collection
    where x.Age < 20
    orderby x.Name
    select new { Code = x.Code, Name = x.Name };
var q = 
    this.Collection
        .Where(x => x.Age < 20)
        .OrderBy(x => x.Name)
        .Select(x => new { Code = x.Code, Name = x.Name });

長いので改行されていますが,単にデリゲートを引数としたメソッドを書き連ねているだけです。 各メソッドの引数では,ラムダ式が使われていることがわかります。

次回の予定

今回は,C#3.0の新機能として有名なLINQをご説明しました。 次回は,C#3.0で記述した簡単なサンプルコードと,これをC#2.0に置き換えたコードをご紹介したいと思います。

これによって,実際にどのような場面で新機能が使えるのか,どれだけ省力化できるのかについてをご理解いただきたいと思います。

著者プロフィール

伊藤達也(いとうたつや)

Microsoft MVP for Visual C#(April 2007 - March 2009)

自他共に認めるC#信者です。

(株)井沢電器設備(ビットラン)にて,主に業務管理システムの設計・開発を行っています。開発に関するご依頼ご相談など常時受け付けております。お気軽にご連絡ください。

Mailito@bitlan.net

コメント

コメントの記入