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

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

はじめに

今年の2月にリリースされたばかりのVisual Studio 2008に含まれるC#3.0ですが、皆さんは既にお使いになっているでしょうか? C#3.0ではC#2.0の豊富な機能に加え、より新しい多くの機能が言語仕様のレベルで追加されています。

そこで、本特集では、C#3.0の新機能をC#2.0のコードと比較することで、ご理解いただこうと考えています。 これによって、見慣れたコードと新しいコードを比較することで、実際に動作を確認しなくても読むだけで容易に理解できるでしょう。

C#3.0によって、どれだけ開発効率を高めることができるのかを、皆さんなりに判断してみてください。

C#3.0の概要

C#3.0は、C#2.0を基盤として、さらに関数スタイルのクラスの作成がサポートされています。

特に、今回のバージョンアップで目立つのは、LINQという新しいテクノロジーの実現と、これに関連した様々な言語拡張が行われたことです。 例えば、クエリ式やラムダ式がC#の言語として表現できたり、型推論の利用もC#2.0の頃に比べるとさらに様々な場面で利用されています。

以下はC#3.0で拡張された主な機能です。

  • 暗黙的型付(Implicitly typed local variables)
  • 自動プロパティ(Automatic Properties)
  • オブジェクト初期化子(Object Initializers)
  • 匿名型(Anonymous types)
  • コレクション初期化子(Collection initializers)
  • 拡張メソッド(Extension methods)
  • ラムダ式(Rambda expressions)
  • LINQ(Language Integrated Query)

実際にC#3.0を使ってコードを書くことで私が一番実感するのは、驚くほどソフトウェアの生産性が向上したことです。

しかし、何よりも、C#3.0の言語仕様の拡張は、開発者にとって大変魅力的な面白さを持っています。 開発者である皆さんなら、この特集を読むことによって、きっと「C#3.0を使って開発をしたい!」と思うことでしょう。

それでは実際のコードを比較しながら見ていきましょう。

暗黙的型付(Implicitly typed local variables)

C#3.0
var i = 5;
var s = "A”;
var f = 2f;
var v = GetValue();
var suzuki = new Member();
var list = new List<string>();
using(var dt = new SampleDataSet.SampleDataTable()) {}
C#2.0
int i = 5;
string s = "A”;
float f = 2f;
double v = GetValue();
Member suzuki = new Member();
List<string> list = new List<string>();
using(SampleDataSet.SampleDataTable dt = new SampleDataSet.SampleDataTable()) {}

varというキーワードがvariant型を想像させるためか、どんな値でも格納できる変数を定義していると誤解する方もいるようですが、両者はまったく違うもので、暗黙的型付けとは、コンパイラが型を推論する機能です。

型推論自身は、C#2.0でも一部使われていましたが、C#3.0では、上記のような変数の宣言を始めとして、様々な場所で利用される程に重要な機能になっています。

上記のC#3.0のコードは、C#2.0のコードのように書いたことと同じ意味を持ちます。 例えば、C#3.0の1行目の「var i = 5;」の記述ですが、5を代入することから、iはint型であることをコンパイラが推論します。 また、4行目の「var v = GetValue();」ですが、これはメソッドの戻り値の型に準じます。

コードエディタ上でインテリセンスやヒントを表示すると、その場でvarと記述したものがintとして定義されていることが確認できます。 varは、ローカル変数の宣言のみに使用が限定されているため、戻り値や引数、フィールド変数に用いることはできません。

自動プロパティ(Automatic Properties)

C#3.0
public object MyValue1 { get; set; }}
public object MyValue2 { get; private set; }}
C#2.0
private object _MyValue1;
public object MyValue {
    get { return this._MyValue1; }
    set { this._MyValue1 = value; }
}

private object _MyValue2;
public object MyValue {
    get { return this._MyValue2; }
    private set { this._MyValue2 = value; }
}

これについては、サンプルコードを見ていただいた通りです。

C#3.0では、フィールド変数にアクセスすることはできません。 従って、初期化する時は、MyValue1プロパティに対して直接行います。

オブジェクト初期化子(Object Initializers)

C#3.0
var suzuki 
    = new Member { Code = 5 , Name = "鈴木”, Age = 31 };
C#2.0
Member suzuki = new Member();
suzuki.Code = 5;
suzuki.Name = "鈴木”;
suzuki.Age = 31;

VBのWithに似ていますが、オブジェクト初期化子は、プロパティや公開されたフィールド変数を初期化するために使用します。

匿名型(Anonymous types)

C#3.0
class Sample {
    private void MyMethod() {
        var suzuki
            = new { Code = 5 , Name = "鈴木”, Age = 31 };
    }
}
C#2.0
class Sample {
    private void MyMethod() {
        Member suzuki = new Member();
        suzuki.Code = 5;
        suzuki.Name = "鈴木”;
        suzuki.Age = 31;
    }
}

class Member {
    private int _Code;
    public int Code {
        get { return this._Code; }
        set { this._Code = value; }
    }
    private string _Name;
    public string Name {
        get { return this._Name; }
        set { this._Name = value; }
    }
    private int _Age;
    public int Age {
        get { return this._Age; }
        set { this._Age = value; }
    }
}

C#3.0のサンプルコードは、オブジェクト初期化子でご紹介したコードから単純に型名を除いたものです。

suzukiというオブジェクトの型は、new {}から暗に生成されます。

本来は、C#2.0のサンプルコードのように実際に値を格納するためのクラスを作成する必要があるのですが、匿名型とオブジェクト初期化子によって簡潔に記述できます。

コレクション初期化子(Collection initializers)

C#3.0
var c = new List<Member> { suzuki, sato, yamada };
C#2.0
List<Member> c = new List<Member>();
c.Add(suzuki);
c.Add(sato);
c.Add(yamada);

これについても、サンプルコードを見ていただいた通りです。 配列の初期化では、既に同じような記述が使えていました。

配列は、単純に値を格納しますが、コレクションはAddメソッドによって要素を追加しますので、表記は似ていますが機能としては異なるものです。

配列初期化子(Array Initializer)

C#3.0
var a = new [] { 1, 2, 3 };
C#2.0
int[] a = { 1, 2, 3 };

C#3.0では型推論が行われています。 そのほかは、コレクション初期化子と同様です。

拡張メソッド(Extension methods)

C#3.0
public void Hoge() {
    var byteLength = "あいうeo".GetByteLength();
}

public static int GetByteLength(this string value) { /* 略 */ }
C#2.0
public void Hoge() {
    var byteLength = GetByteLength("あいうeo”);
}

public static int GetByteLength(string value) { /* 略 */ }

拡張メソッドによって、既存のクラスに対して外部からメソッドを追加できます。

上記は、共に「あいうeo」という文字列のバイト数を取得する処理を、C#3.0では拡張メソッドによって、C#2.0では静的メソッドによって実現した例です。 拡張メソッドによって、string型に直接GetByteLengthメソッドを外部から追加しています。

拡張メソッドを書く場合は、⁠string value」引数の直前に「this」キーワードを付加します。 上記の例では、string型のvalueには「あいうeo」が格納されていることになります。

拡張メソッドは同一の名前空間に対して有効です。 また、using句で指定することで、別の名前空間で記述した拡張メソッドも有効になります。

例えば「System.Linq」名前空間をusingすることで、たくさんの拡張メソッドが利用できるようになります。 次回以降ご説明するLINQでは、この拡張メソッドを使うことによって、非常に便利な機能が実現できるようになっています。

次回の予定

今回は、言語構文を覚えるだけで比較的簡単に覚えられる機能について中心にご説明しました。

次回は、もう少し複雑なラムダ式についてをご説明していきたいと思います。

おすすめ記事

記事・ニュース一覧