fc2ブログ

初心者のためのC#プログラミング本格入門116 - 機能の拡張を考えつつ学習しよう

 この記事は初心者のためのC#プログラミング本格入門115の続きです。前回は、エラーが発生した際に、発生源を特定する方法の例外処理について解説しました。今回は、学習を継続するためのコツと、さらなるプログラミングの考え方について解説します。
 皆様は何かの学習が続かなかった経験がありませんか?何かの学習を使用としたけど、それが続かないというのはよく聞く話です。かくいう私も、英語の学習がなかなか継続できなくて困っています。そういった誰にもある学習の壁が「継続」なのです。学習は意外と継続するのが難しいです。でも、心配貼りません。プログラミングの学習を継続するコツと方法を知っています。これから、学習を継続する方法とコツについて書きます。
 今回までで、結構プログラムを作りました。簡単な計算機を作りましたし、テストもやったし、データを追加できますし、削除もできるデータ構造も作りました。きっと、多くの初心者の方は結構満足したと思います。でも、プログラミングの世界はまだまだ終わりではありません。もっと楽しいことがあります。それを知るにはやはり学習が必要です。しかし、当然初心者の方はプログラミングの世界をまだよく知らないので、学習する方法はわからないと思います。実は、そんな手探り状態でも学習ができる方法があります。それは、素直に問いかける事です。サンプルをもとに実際にやってみます。
 基本的な機能を持つリスト(サンプルプログラム)を作りました。このオブジェクトは、データを管理するためのもので、データの追加・削除・参照ができます。ここで、素直になって考えてみましょう。今のところ、データの追加と削除は、最後の位置にしかできません。ですが、最後の位置にこだわる必要はありません。必ず最後の位置なのは不便です。好きな場所にデータを追加したり、削除したりできたら便利です。こんな具合に、リラックスして素直に思いついたことを実際にやってみましょう
 オブジェクトに「データを任意の場所に追加する」といった新しい機能を付け加える場合、インタフェースとなるメソッドの名前と引数を考えます。そして、今までやってきたように、自分が望むプログラムが作れたのかチェックするテストを考えます。
 簡単テストプログラムを掲載しますので参考にしてください。

//関係のないプログラムは省略しています
class SimpleListTest : Test
{
   private SimpleList target;

    //全てのテストを返えします
    protected override System.Action[ ] GetTests()
    {
        System.Action[ ] tests = new System.Action[ ] {
            this.OneElementAdd,
            this.OneElementRemove,
            this.CurrentTest,
            this.AddElementCheck,
            this.EnumeratorWhenRemoveElement,
            this.ForeEachTest,
            this.ForeEachTest2, 
            this.InsertTest //←忘れないように注意
        };
        return tests;
    }

    private void InsertTest()
    {
        base.Execute( );

        //初期値を用意する
        int count = 10;
        for ( int i = 0 ; i < count ; ++i ) {
            this.target.Add( i );
        }

        //位置を指定して値を挿入したい
        int index = 5;
        int value = 100;
        this.target.Insert(index, value );

        //正しく挿入されたかチェック
        if ( value != this.target[ index ] ) {
            string message =
                "指定された位置に値を挿入できませんでした。";
            throw new TestFail( message );
        }
    }
}
以上のようにテストは最初簡単にして後で追加していきます。何故ならば、最初から難しいテストを考えると、これから作るプログラムではなく、テストのプログラムで悩んで、学習意欲がそがれてしまうからです。そんなことになってしまっては、もともこうもありません。くれぐれも最初は、一目でわかるぐらい簡単にしましょう。
 次回から「データを任意の場所に追加する機能」を作ります。お楽しみに。
スポンサーサイト



テーマ : プログラミング
ジャンル : コンピュータ

宣言型プログラミングって何?

 マルチコアのCPUが当たり前になった今、並列処理に強い宣言型プログラミングが今まで以上に注目されています。例えば、昔は命令型プログラミングが当たり前だったC#とVBも、ラムダ式やクエリ式などによる宣言型プログラミングが当たり前になっています。しかしながら、宣言型プログラミングはまだまだ浸透しておらず、古くからプログラミングをしている人は、宣言型プログラミングを否定的に見る傾向があると感じます。そこで今回、そんな現代の必須知識となった宣言型プログラミングの概要を解説します。
 宣言型プログラミングを一言でいうと、「状態に依存せず、どうやってではなく何なのかを記述していくプログラミング」です。状態に依存するとは何でしょうか?それは、命令型プログラミングでは当たり前にやっていたことです。しかし、命令型プログラミングに慣れている人にとって意識するのが難しいと思います。これから噛み砕いて説明します。
 状態の簡単な例を挙げると、「変数値の変化」です。命令型プログラミングでは、変数の値を変えていきます。合計値を計算する過程を思い浮かべると分かりやすいと思います。合計値を命令型プログラミングで求める場合、総合計を格納する変数を宣言し、ループ構文を使って繰り返し値を加算していきます。この時、総合計を表わす変数に値を加算していくのが命令型プログラミングのやり方です。一方、宣言型プログラミングでは、個々の値を関数に渡して総合計を得ると考えます。つまり、計算過程に注目せず、繰り返して加算するという「どうやって」ではなく、総合計とは「何か」と考えるのです。
 普通の人は「どうやって」と「何か」のどちらに注目するのかは、些細な差だと思えるでしょう。結局はプログラミングであり、細かく機械に指示する必要があります。「何か」に注目していても、いつかは「どうやって」に行き着きます。しかし、この些細な考え方の差は意外と大きなものです。
 一番差を感じやすいのは、並列処理プログラミングです。並列処理を「どうやって」と考えると、状態の変化を制御するのが難しくなります。何故ならば、複数のCPUがあっても、メモリは一つであり、一つの目盛を複数のプログラムが読み書きするのですから、どうしても不都合が生じます。「どうやって」を考えると、この不都合で頭がいっぱいになります。一方、「何か」に注目すると、計算過程を無視できるので、状態変化と整合性に注目しなくてもよいようになります。これはあくまでも一例です。並列処理に限らず、「どうやって」ではなく「何か」を記述すると、プログラムの主体が明確になり読みやすくなります。また、状態を無視出来るのでテストも行いやすくなります。そういったことから近年、宣言型プログラミングの需要が高まっています。
 もしかしたら、昔からプログラミングをしている人は、命令型プログラミングの考え方に染まって、宣言型プログラミングの考えに違和感や抵抗感を覚えるかもしれません。しかしながら、これからのソフトウェアやシステムを考えたとき、宣言型プログラミングは避けて通れません。考え方そのものは簡単なので、まずは覚えるとよいと思います。宣言型と命令型の思想について判断を下すのは、覚えた後からでも遅くはないはずです。それに、私たちはプロであり、お客様が求める物を作ることを第一のはずです。求められているものは素早く習得し、好みの問題は後でじっくりと考えるのが最善だと思います。

テーマ : プログラミング
ジャンル : コンピュータ

VB文法リファレンス - クエリ式

概要
 場所や形式に関係なく、データを取り扱います。

使用に適した状況
 データを扱う状況全てです。今のところは、データの読み出しに限定されていますが、いずれは、データの変更にも使用できるようになるでしょう。

サンプル

'------------------------------------------------------------

'クエリ式

'------------------------------------------------------------
Imports System
Imports System.Collections.Generic
Imports System.Linq

Class Member
    Public Property Count As Integer
    Public Property Name As String
    Public Sub New(ByVal id As Integer, ByVal name As String)
        Me.Count = id
        Me.Name = name
    End Sub
End Class

Module Sample

    Sub Main()

        'データを準備
        Dim list As List(Of Member) = New List(Of Member)() From {
            New Member(11, "A"),
            New Member(20, "B"),
            New Member(14, "C"),
            New Member(10, "D"),
            New Member(9, "E")
        }
        For Each m As Member In list
            Console.WriteLine("Count:{0}, Name:{1}", m.Count, m.Name)
        Next
        Console.WriteLine()

        'クエリ式を実行
        Console.WriteLine("購入数が0を超えるメンバーを名前の降順で表示します・・・")
        Dim result = From m In list
                Where m.Count > 10
                Order By m.Name Descending
                Select m.Name
        For Each m As String In result
            Console.WriteLine("Name:{0}", m)
        Next
        Console.WriteLine()

        '終了
        Console.ReadLine()
    End Sub

End Module


文法
 いろいろな書き方ができるSelect、Order By、Where 、Fromの四つの句を、1度に全て使用した例です。SQLとは違い、from句が最初に書かれている点に注意してください。SQLはFROM句の位置が、宣言型としては不適切だと指摘されていました。マイクロソフトはそれを解消したのでしょう。SQLに慣れていると違和感を覚えるでしょうが、宣言型としては正しい形式です。この形式だと、構文解析もやりやすく、思考の流れに沿っていると思います。
 今回は一目で概要がわかるようにしましたが、クエリ式はLINQプログラミングで使用します。LINQプログラミングは、奥が深いものなのでリファレンスでは入口しか紹介できませんでした。詳しくは今後書く予定の別の記事を参考にしてください。

解説
 情報システムにおいて、データは必須要素です。しかしながら、そのデータの位置もしくは、データの形式により、使用技術が違いました。例えば、データベースにある場合はSQL、XML形式のファイルにある場合はXQueryなど、データの内容は同じでも、様々な技術を覚え、書き分ける必要がありました。LINQはその問題を解決するべく作られて技術であり、クエリ式はLINQプログラミングをやりやすく行うための言語要素です。VBを使用すると、LINQプログラミングがやりやすくなります。
 LINQプログラミングと書くと、一般のプログラマーに関係がないように思う人が居るかもしれません。しかしながら、データを全く使用しない実務プログラミングはほぼありません。全ての人が関係のある、それこそループ構文ぐらい使用頻度が高いものです。
 なお、クエリ式のサポートにより、VBは宣言型プログラミングをするのが一般的になっています。このブログでは、敷居を低くするために極力避けていました。ですが、現在のVBプログラミングは、クエリ式を使った宣言型プログラミングをするのが普通です。どの言語でもループなどの文法は必須です。それと同様に、VBを使用するならば、クエリ式は必須だと考えるとよいでしょう。

テーマ : プログラミング
ジャンル : コンピュータ

C#文法リファレンス - クエリ式

概要
 場所や形式に関係なく、データを取り扱います。

使用に適した状況
 データを扱う状況全てです。今のところは、データの読み出しに限定されていますが、いずれは、データの変更にも使用できるようになるでしょう。

サンプル

/*----------------------------------------------------
 * 
 *  クエリ式
 *  
 ----------------------------------------------------*/
using System;
using System.Collections.Generic;
using System.Linq;


class Member
{
    public int Count { get; set; }
    public string Name { get; set; }
    public Member( int count, string name )
    {
        this.Count = count;
        this.Name = name;
    }
}
class Sample
{
    static void Main()
    {
        //データを準備
        List<Member> list = new List<Member>( ) {
            new Member( 11, "A"),
            new Member( 20, "B"),
            new Member( 14, "C"),
            new Member( 10, "D"),
            new Member( 9, "E")
        };
        foreach ( Member m in list ) {
            Console.WriteLine( "Count:{0}, Name:{1}", m.Count, m.Name );
        }
        Console.WriteLine( );

        //クエリ式を実行
        Console.WriteLine( 
            "購入数が10を超える館員を名前の降順で表示します・・・" );
        var result = from m in list
                     where m.Count > 10
                     orderby m.Name descending
                     select m.Name;
        foreach ( string m in result ) {
            Console.WriteLine( "Name:{0}", m );
        }
        Console.WriteLine( );

        //終了
        Console.ReadLine( );
    }
}


文法
 いろいろな書き方ができるselect、order by、where 、fromの四つの句を、1度に全て使用した例です。SQLとは違い、from句が最初に書かれている点に注意してください。SQLはFROM句の位置が、宣言型としては不適切だと指摘されていました。マイクロソフトはそれを解消したのでしょう。SQLに慣れていると違和感を覚えるでしょうが、宣言型としては正しい形式です。この形式だと、構文解析もやりやすく、思考の流れに沿っていると思います。
 今回は一目で概要がわかるようにしましたが、クエリ式はLINQプログラミングで使用します。LINQプログラミングは、奥が深いものなのでリファレンスでは入口しか紹介できませんでした。詳しくは今後書く予定の別の記事を参考にしてください。

解説
 情報システムにおいて、データは必須要素です。しかしながら、そのデータの位置もしくは、データの形式により、使用技術が違いました。例えば、データベースにある場合はSQL、XML形式のファイルにある場合はXQueryなど、データの内容は同じでも、様々な技術を覚え、書き分ける必要がありました。LINQはその問題を解決するべく作られて技術であり、クエリ式はLINQプログラミングをやりやすく行うための言語要素です。C#を使用すると、LINQプログラミングがやりやすくなります。
 LINQプログラミングと書くと、一般のプログラマーに関係がないように思う人が居るかもしれません。しかしながら、データを全く使用しない実務プログラミングはほぼありません。全ての人が関係のある、それこそループ構文ぐらい使用頻度が高いものです。
 なお、クエリ式のサポートにより、C#は宣言型プログラミングをするのが一般的になっています。このブログでは、敷居を低くするために極力避けていました。ですが、現在のC#プログラミングは、クエリ式を使った宣言型プログラミングをするのが普通です。どの言語でもループなどの文法は必須です。それと同様に、C#を使用するならば、クエリ式は必須だと考えるとよいでしょう。

テーマ : プログラミング
ジャンル : コンピュータ

ネタつつき153 - 才能を気にする人へ

 どうやら巷には、才能という言葉に心が揺れている人が沢山いるようです。今回はそういった人のために書きます。結論から言いますと、才能なんて言葉はどうでもいいものです。これからその理由を書きます。
 私は度々人から、情報技術者(プログラマー、システムエンジニアなど)としての才能の有無を聞かれます。正直に言って、私は才能というものがわかりません。才能というものは、数値化できないいい加減なものですし、あってすぐの人の適正なんてわかりません。私自身、才能というものについて考えたことがありませんから、才能を気にする人に疑問を感じてしまいます。
 才能というものを他人に聞いてどうするのでしょうか?万が一、才能がないといわれた時はどうするのでしょうか?たとえ才能があるといわれても、私個人のいい加減な印象論を聞いてどうするのでしょうか?私には理解できません。ですから、こういった質問をされた際に、私は何故そんなことを聞くのかと尋ね返したことがあります。そうすると、色々な答えが返ってきましたが、おおむね精神的な安定を求めているようでした。そのような人々に私はこうアドバイスします。「才能なんていう曖昧なものは気にする必要がない。貴方の意思が問題です。」と。
 私がもし他人から才能がないといわれたら、少しは嫌な気分になるでしょう。しかしながら、影響は全く受けません。何故ならば、才能があろうがなかろうが、情報技術およびこの仕事が好きだからです。仮に才能がなかったとしても、やりたいものはやりたい。ただそれだけなのです。他人の言葉なんて関係ありません。その結果どうなるかは、やってみないと分かりません。やる前から悩んでも仕方がありません。
 もし貴方が「お前には才能がない」といわれたら、具体的な理由を聞いておきましょう。大半はいい加減なものでしょうし、仮に返ってきたらそこを直せばいいのです。気にするタイプの人は聞き流せばいいでしょう。「自分がやりたいからやる」それ以外の何もいりません。貴方の人生は、貴方のものなのです。他者の言葉に惑わず、ただひたすらに楽しみましょう。

テーマ : 文明・文化&思想
ジャンル : 学問・文化・芸術

VB文法リファレンス - 変数名の省略

概要
 変数名を省略してプログラムを読みやすくします。

使用に適した状況
 同じ変数に対して、1連の処理があり、なおかつメソッドとして纏めるのが不適切な場合。また、1連のプログラムの主役(注目するべきオブジェクト)を読み手に示したい場合も適しています。

サンプル

'---------------------------------------------

'Withステートメントによる変数名の省略

'---------------------------------------------
Imports System

Class Customer
    Public Property ID As Integer
    Public Property Name As String
End Class

Class Product
    Public Property Name As String
    Public Property Price As Integer
End Class

Module Sample

    Sub Main()

        '変数名を省略できる
        Dim target As Customer = New Customer()
        With target
            .ID = 10
            .Name = "山田太郎"
        End With

        '入れ子構造も可能
        With target
            Dim soldGoods As Product = New Product()
            soldGoods.Name = "ポテチ"
            With soldGoods
                Console.WriteLine("どっちが表示される?:{0}", .Name)
                '外側の変数名を省略できない
                'Console.WriteLine("購入者:{0}", .ID)
            End With
        End With

        '終了
        Console.ReadLine()
    End Sub

End Module


文法
 Withキーワードと省略したい変数名を指定し、End Withで終了します。省略した変数名は「 . 」(ピリオド記号)で指定します。入れ子構造にすることもできます。しかしながら、入れ子構造にした場合、予期せぬ動作をする恐れがあります。入れ子構造は慎重に使用するべきです。

解説
 同じ変数に対して、複数のプロパティの値を設定したいときが多々あります。また、1つのオブジェクトが主となるプログラムが続く状況があります。そうした状況で、Withステートメントを使用すると、読み手に主となるオブジェクトを知らせることができます
 ただし、変数名を打つのが面倒だという理由で多用してはなりません。逆にプログラムが読みにくくなる恐れがあります。

テーマ : プログラミング
ジャンル : コンピュータ

VB文法リファレンス - 初期化子

概要
 オブジェクトの初期化と、プロパティ値の設定を簡単に記述するための文法です。これにより、利便性のためにコンストラクタを用意しなくてもよいようになります。

使用に適した状況
 利便性や可読性のためだけに、余計なコンストラクタが増えて困っている。もしくは、1つも無駄なコンストラクタを定義したくないときに使用します。オブジェクト指向設計の観点から言って、そういった本質とは関係のないコンストラクタは、実装するべきではないので常に使えると言ってもよいと思います。

サンプル

'---------------------------------------------

'初期化子

'---------------------------------------------
Imports System.Collections.Generic

Class Member
    Public Property ID As Integer
    Public Property Name As String

    Public Overrides Function ToString() As String
        Return String.Format(
            "ID:{0}, Name:{1}", Me.ID, Me.Name)
    End Function
End Class

Module Initializers

    Sub Main()
        '名前がある通常の型を初期化
        Dim obj As Member = New Member With {.ID = 10, .Name = "山田太郎"}
        Dim obj1 = New Member With {.ID = 20, .Name = "案山子"}

        '匿名型の初期化
        Dim obj2 = New With {.ID = 200, .Name = "山田花子"}

        'コレクションの初期化
        Console.WriteLine("コレクション初期化子を使用します")
        Dim memberList As List(Of Member) = New List(Of Member) From
        {
            New Member With {.ID = 10, .Name = "山田太郎"},
            New Member With {.ID = 20, .Name = "山田花子"}
        }
        For Each e As Member In memberList
            Console.WriteLine(e.ToString())
        Next
        Console.WriteLine()

        '終了
        Console.WriteLine("終了")
        Console.ReadLine()

    End Sub

End Module


文法
 New Withと{}を使用して、その中で「.プロパティ名 = 値 」と書きます。細かく分類すると、単体のオブジェクト初期化子と、複数を指定したい場合の>コレクション初期化子があります。しかし、2つの初期化子には、共通したパターンの書き方があるので困らないと思います。違いは、コレクション初期化子にはFromキーワードを使用する点です。
 なおNew Withキーワードは、New演算子とWithステートメントと併用していると覚えると良いでしょう。VBをよく使っている人にとって、Withステートメントはなじみ深く、プロパティ名の前のドットを忘れないようにするのに効果的だと思います。

解説
 オブジェクトを定義しているとき、オブジェクトを初期化してから、プロパティに値を設定するのが面倒かつ美しくありません。本当に表現したい事が見えにくくなります
 それでプログラマーは、初期化用のコンストラクタを用意します。こうすることにより、一度に初期化とプロパティの設定を行うことが可能となります。しかしながら、設計面から考えると、余計なコンストラクタを用意することは望ましくありません。何故ならば、本来は実装する必要がない、設計とは無関係なコードが入り込むからです。さらに、プロパティの組み合わせは莫大な数になりえます。その両方を解決する文法が初期化子です。初期化子があれば、実装者は無駄なコンストラクタを定義する必要がなくなり、なおかつオブジェクトの使用者も簡潔に記述できます。糖衣文だといわれることもありますが、設計と実装面を考えた非常に良い文法だと思います。

テーマ : プログラミング
ジャンル : コンピュータ

VB文法リファレンス - 匿名型

概要
 メソッド内でのみ使用する、データしか持たない単純な型を簡潔な記述で生成します。

使用に適した状況
 特定のメソッド内で、一時的に作成する必要がある、データしか持たない単純な型が必要な場合。

サンプル

'------------------------------------------------------------

'匿名型

'------------------------------------------------------------
Imports System
Module AnonymousTypes

    Sub Main()
        '型を省略し、New Withを使用すると
        'コンパイラが自動的に型を作成する
        Dim obj = New With {.Name = "山田太郎", .ID = 10}
        Dim obj1 = New With {.Name = "山田花子", .ID = 20}
        Dim obj2 = New With {.Name = "山田太郎", .ID = 10}

        '匿名型のインスタンスを変更可能
        obj.ID = 20
        obj.Name = "山田次郎"
        obj.ID = 10
        obj.Name = "山田太郎"

        '匿名型のインスタンスは自身のみ等価
        Console.WriteLine(
            "山田太郎(ID:10)と山田花子(ID:20)の等価性:{0}",
             obj.Equals(obj1))
        Console.WriteLine(
            "山田太郎(ID:10)と同じインスタンスの等価性:{0}",
            obj.Equals(obj))
        Console.WriteLine(
            "山田太郎(ID:10)と内容が同じ別のインスタンスの等価性:{0}",
            obj.Equals(obj2))
        Console.WriteLine()

        'キーを指定すると、ハッシュ値と等価に使用できる。
        Console.WriteLine("キーを指定して等価性を判定できるようにします・・・")
        Dim obj3 = New With {.Name = "山田太郎", Key .ID = 10}
        Console.WriteLine(
            "内容が同じインスタンスを比較(Keyの指定なし):{0}",
            obj.Equals(obj3)) 'Keyプロパティの指定がないのでFalse
        Dim obj4 = New With {.Name = "山田太郎", Key .ID = 10}
        Console.WriteLine(
            "内容が同じインスタンスを比較(Keyの指定あり):{0}",
            obj3.Equals(obj4))
        Dim obj5 = New With {Key .Name = "山田太郎", Key .ID = 10}
        Console.WriteLine(
            "内容は同じだが、Keyで指定するプロパティの値が違うインスタンスを比較:{0}",
            obj3.Equals(obj5)) 'Keyに指定するプロパティが違うのでFalse
        'Console.WriteLine(obj3 = obj4) '等価演算子が定義されていないのでエラー
        Console.WriteLine()

        'キー指定したプロパティは変更できない
        'obj3.ID = 100
        obj3.Name = "山田次郎"

        '位置でも指定できる
        '※等価性の判定に注意
        Dim name As String = "山田太郎"
        Dim id As Integer = 15
        Dim obj6 = New With {name, id}
        'Console.WriteLine( "{0}と{1}は同じ? {2}",
        '    obj, obj5, obj == obj5 )

        '終了
        Console.ReadLine()

    End Sub

End Module

文法
 匿名型は、New Withキーワードと{}を使用して指定します。見た目は、型推論(ローカル型の推論)と初期化子を組み合わせたものです。しかし、プロパティの値を位置で指定できるところが違います。メソッドは指定できず、戻り値の型を匿名型にすることはできません。他にも細かい制限はありますが、一時的に使用するデータとして考えれば理解しやすいと思います。
 通常のクラスと比べると制限は厳しいものの、変更の有無を柔軟に指定できます。Keyキーワードを指定すると、そのプロパティは不変となり、等価判定に有効に働きます。Equalsメソッドやプロパティのコードまでコンパイラが自動的に生成してくれます。

解説
 使用方法を詳しく説明します。他の方法を考えると、プライベート型を作成する方法もあります。しかし、特定のメソッド内でのみ使用する単純なオブジェクトを型として定義すると、複数のメソッドで使用する型なのか、特定のメソッド内のみ使用する型なのかが分かりません。その判別は一見どうでもよいことですが、複数のメンバーで大量のコードを保守する必要がある実務において、余計な型を定義すると混乱を生みます。特定のメソッド内でのみ使用しない単純なオブジェクトは、匿名型として扱うとよいでしょう。
 なお、匿名オブジェクトには、データとして考えるとよいと分かりやすいと思います。厳しい制限が気になるかもしれませんが、一時データとしてみると極めて自然な制限だと思います。

テーマ : プログラミング
ジャンル : コンピュータ

VB文法リファレンス - 拡張メソッド

概要
 継承を使わず、既存のオブジェクトに振る舞い(メソッド)を追加します。言い換えると、既存オブジェクトを拡張しているといえます。

使用に適した状況
 無暗にオブジェクトの数を増やさず、既存オブジェクトに対して、特定の問題領域(ドメイン)内のみ有効な振る舞いを追加したい。もしくは、既存の型が継承不可になっているとき、どうしても型の振る舞いを増やしたい。ただし、継承不可のオブジェクトの振る舞いを追加したい場合は、合成オブジェクトやデザインパターンを使用したほうが良いと思います。

サンプル

'----------------------------------------------------
' 
'  拡張メソッド
'  
'-----------------------------------------------------
Imports System
Imports System.Runtime.CompilerServices '拡張メソッドを定義する為に必要

Namespace Data

    Class Customer

        Private _id As Integer
        Public ReadOnly Property ID As Integer
            Get
                Return Me._id
            End Get
        End Property

        Private _name As String
        Public ReadOnly Property Name As String
            Get
                Return Me._name
            End Get
        End Property

        Public Sub New(ByVal id As Integer, ByVal name As String)
            Me._id = ID
            Me._name = Name
        End Sub

    End Class
End Namespace

Namespace Service

    '拡張メソッドはモジュールでしか定義できない
    Module Sales

        '拡張メソッド
        '属性を指定する
        <Extension()>
        Public Function GetSpecialPrice(ByVal c As Data.Customer, ByVal basePrice As Integer) As Double
            Return basePrice * 0.8
        End Function

        Public Sub Main()
            Dim obj As Data.Customer = New Data.Customer(100, "山田商事")
            Dim price As Integer = 100
            Console.WriteLine(
                "{0}様のご購入金額は{1}万円( 基本価格{2}万円 )です。",
                obj.Name, obj.GetSpecialPrice(price), price)
            Console.ReadLine()
        End Sub

    End Module
End Namespace


文法
 モジュールを用意し、Extension属性をつけてメソッドを宣言します。します。この宣言した関数が付け加えられる型(拡張される型)は、最初に宣言した引数(パラメーター)です。
 これは文法の条件ではないのですが、拡張メソッドの使用を意識的に選択できるようにするために、名前空間との併用が望ましいと思われます。プログラマーが意識することなく拡張メソッドが適用されてしまうと、自分が定義した覚えのないメソッドがあることから混乱が生じる恐れがあります。メソッドのオーバーロードと絡むと、コンパイラが選択するメソッドのルールが複雑化します。

解説
 例えば、顧客データの様なオブジェクトは、各部門別が違う用途に使用します。この様な使いまわすオブジェクトを表現するために、子オブジェクトを定義する方法を採ると、オブジェクトの数が無暗に増え、保守性低下などの悪影響を及ぼします。また結果として、システムの拡張が妨げられます。
 この現象を避ける方法のうちの1つが拡張メソッドです。上手く拡張メソッドを使用すれば、効果が薄い子オブジェクトの増殖を減らせます。ただし、あまりにも特殊な動作をするオブジェクトを定義したい場合は、素直に継承を使用したほうが良いでしょう。
 拡張メソッドのお手本はLINQです。LINQで使用されているオブジェクトを調べると、拡張メソッドの上手な使い方が学べます。

テーマ : プログラミング
ジャンル : コンピュータ

C#文法リファレンス - 可変長引数

概要
 任意の数の値を指定できる、メソッドやコンストラクタのパラメーターを定義します。

使用に適した状況
 ConsoleオブジェクトのWriteLineメソッドのように、パラメーターとして渡す値の数が予測できない場合に使用します。

サンプル

/*----------------------------------------------------
 * 
 *  可変長パラメーター
 *  
 ----------------------------------------------------*/
using System;

class Sample
{
    //通常のメソッド
    private static int Plus( int[ ] values )
    {
        int result = 0;
        foreach ( int value in values ) {
            result += value;
        }
        return result;
    }

    //可変長引数のメソッド
    private static int Plus2( params int[] values )
    {
        int result = 0;
        foreach ( int value in values ) {
            result += value;
        }
        return result;
    }

    static void Main()
    {
        //配列値の指定は冗長
        Console.WriteLine( "10 + 20 = {0}",
            Plus(  new int[] { 10, 20 } ) );
        Console.WriteLine( "10 + 20 + 30 = {0}",
            Plus(  new int[] { 10, 20, 30 } ) );
        Console.WriteLine( );

        //任意の数の値を簡潔に指定できる
        Console.WriteLine( "10 + 20 = {0}",
            Plus2( 10, 20 ) );
        Console.WriteLine( "10 + 20 + 30 = {0}",
            Plus2( 10, 20, 30 ) );
        Console.WriteLine( );

        //終了
        Console.ReadLine( );
    }
}


文法
 型の左側に「params」キーワードをつけて、パラメーターを定義します。なお、キーワードをつけたメソッドと、キーワードをつけていないメソッドを同じ名前で定義できません。

解説
 予めパラメーターとして渡す数が予測できない場合、オーバーロードを使用するのは不適切です。何故ならば、1つの値を指定できるメソッド、2つの値を指定できるメソッド、…という具合に際限がないからです。仮に9個までメソッドを要しても、10の値を指定されるかもしれません。
ですから通常は、配列を受け取るメソッドを用意します。しかしながら、今度は簡潔なコードになりません。簡潔に記述するには、メソッドの定義で可変長引数であることを、専用のキーワードで明示します。

テーマ : プログラミング
ジャンル : コンピュータ

プロフィール

インドリ

Author:インドリ
みなさん、はじめまして、
コンニチハ。

ボクは、無限の夢(infinity dream)を持つネタ好きな虹色の鳥インドリ(in dre)です。
色々な情報処理技術を啄ばむから楽しみにしてね。

http://twitter.com/indori
は別人による嫌がらせ行為です。
私とは関係ないので注意して下さい。
次はなりすましブログなどをするかもしれませんが、ここ以外でブログをするつもりがないので、ここ以外にインドリのブログがあったとしても無視してください。


何度言っても分からない人がいるので、ここにコメント欄へ書き込むときの注意事項を書きます。


一、社会人としてのマナーをわきまえましょう。
一、妄想に基づく書き込みを止めてください。
一、暴言の類は書かないで下さい。
一、某誹謗中傷サイトの書き込みは彼らの妄想に基づく書き込みですから無視して、ここへ書き込まないで下さい。
一、コメント書く前に他のコメントよく読んでから行って下さい。
一、言いがかかり等の行為を禁止します。
一、その他常識的に考えて迷惑なコメントはしないで下さい。


以上のルールを守れない人のコメントは削除します。



利用上の注意
ここに紹介してある文章およびプログラムコードは正確であるように心がけておりますが、内容を保証するものではありません。当サイトの内容によって生じた損害については、一切の責任を負いませんので御了承ください。


執筆したCodeZineの記事


【VB.NETで仮想CPUを作ろう】

  1. VB.NETで仮想CPUを作ろう
  2. レジスタの実装
  3. 仮想CPUのGUI化
  4. テストドライバの改良
  5. CPUの基礎動作の実装
  6. MOV命令の実装
  7. ADD命令実装
  8. SUB命令実装
  9. INC命令&DEC命令の実装と命令長
  10. MLU命令の実装とModR/Mについて
  11. DIV命令の実装とイベント設計について
  12. 機械語駆動式 関数電卓を作ろう!
  13. 機械語駆動式 関数電卓を作ろう! 解答編(前半)
  14. 機械語駆動式 関数電卓を作ろう! 解答編(後半)


【仮想ネットワーク実装でTCP/IPを学ぼう】
  1. TCP/IPの基礎と勘所
  2. ネットワークアクセス層の勘所
  3. インターネット層の勘所
  4. トランスポート層の勘所
  5. アプリケーション層の勘所
  6. セキュリティの基礎と仮想ネットワークの仕様
  7. GDI+と独自プロトコルの定義



【並列化】
インテル Parallel Studioを使って並列化プログラミングを試してみた
並列プログラミングの効率的なデバッグを実現する「Parallel Inspector」


【TBBシリーズ】
  1. インテル スレッディング・ビルディング・ブロックの概要
  2. インテルTBBから学ぶループの並列化
  3. スレッドセーフとインテルTBBのコンテナ
  4. インテルTBBのスレッドクラス


【OpenMPシリーズ】
  1. OpenMPの基礎構文
  2. OpenMPの実行時ライブラリと並列ループ
  3. OpenMPのメモリモデルとfork- joinモデル

最近の記事
最近のコメント
月別アーカイブ
カテゴリ
Ada (9)
COBOL (5)
C (9)
C++ (11)
C# (370)
D (25)
Java (8)
Perl (1)
Ruby (14)
PHP (2)
Boo (2)
Cobra (2)
LISP (6)
F# (33)
HTML (0)
XHTML (0)
CSS (0)
XML (0)
XSLT (0)
Scala (4)
WPF (0)
WF (2)
WCF (0)
LINQ (4)
MONO (5)
Linux (0)
MySQL (0)
ブログ内検索
リンク
最近のトラックバック
RSSフィード
ブロとも申請フォーム

この人とブロともになる

QRコード
FC2カウンター