忍者ブログ

Memeplexes

プログラミング、3DCGとその他いろいろについて

"Orcas"とC# 3.0 その2 拡張メソッド

C# 3.0 には拡張メソッドなるものがあるそうで、
あるクラスのメソッドを後から増やせるそうです。
using System;

class Person { public int Age { get; set; } }

static class PersonExtension
{
    public static bool IsAdult(this Person person) {
        return person.Age >= 20;
    }
}

class Program
{
    static void Main(string[] args)
    {
        Person child = new Person { Age = 10 };
        Person father = new Person { Age = 35 };
        Console.WriteLine(child.IsAdult()); //False
        Console.WriteLine(father.IsAdult()); //True 
    }
}

一見したところこれはクラスの凝集性を破壊するだけ
のように思えます。
別々に書く意味は全くありません。
PersonクラスにIsAdultメソッドも書くべきです。
実際、公式でもあまり軽々しく使うなと言われているようです。

ではなぜ拡張メソッドが存在するかと言うと、
1つにはインターフェースが実装しやすくなる
と言うのがあるようです。

using System;
using System.IO;

interface IPerson { int Age { get; set; } }
class Person : IPerson { public int Age { get; set; } }
class PersonFile : IPerson
{
    public int Age
    {
        get { return Int32.Parse(File.ReadAllText("person.txt")); }
        set { File.WriteAllText("person.txt", value.ToString()); }
    }
}

static class PersonExtension
{
    public static bool IsAdult(this IPerson person)
    {
        return person.Age >= 20;
    }
}

class Program
{
    static void Main(string[] args)
    {
        Person child = new Person { Age = 10 };
        PersonFile father = new PersonFile { Age = 35 };
        Console.WriteLine(child.IsAdult());
        Console.WriteLine(father.IsAdult());
    }
}
とりあえずPersonクラスに似た、PersonFileクラスを作りました。
メモリではなくファイルに年齢を格納します。
(ここは本当はファイルではなくネットワークに接続する
Proxyパターンにするべきなのでしょうけど長くなると困りますからね。)

もしPersonのインターフェースを作った場合、
それを使ってIsAdult()を呼べるべきです。

しかしそうすると、もし拡張メソッドを使わなかったら、
全ての実装したクラスでも
Age >= 20;
とやらなければなりません。

新たにクラスを1つ作るたびに重複が多くなってしまいます。

拡張メソッドを使えばその問題が解決されます。
Age >= 20;
は一ヶ所、拡張メソッドの中に集中します。
すばらしい。

実際の.netライブラリではオブジェクトのコレクション(?)
を表すIEnumerableインターフェースが拡張されています。

IEnumerableはオブジェクトを列挙する能力しかありませんが、
System.Linq.Enumerableによってさまざまな便利な能力を
付与されています。

拍手[1回]

PR