fc2ブログ

VB文法リファレンス - タイプコンストラクタ

概要
 型共通の初期化処理を定義します。デフォルトコンストラクタと似ていますが、デフォルトコンストラクタは、インスタンスの初期化ですので違う機能です。

使用に適した状況
 型に共通して存在する初期化処理が必要な場合。インスタンスごとに必要な処理か、型に必要な処理なのかをよく考えて使い分ける必要があります。

サンプル

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

'コンストラクタ

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

Class ReferenceType

    Public Value As Integer
    Public Shared BaseValue As Integer

    Shared Sub New()
        BaseValue = 10 '静的な変数などを初期化
        Console.WriteLine("参照型のタイプコンストラクタが呼び出されました。")
    End Sub

    Public Overrides Function ToString() As String
        Return "値は" & (Me.Value + BaseValue).ToString()
    End Function

End Class

Structure ValueType

    Public Value As Integer
    Public Shared BaseValue As Integer

    Shared Sub New()
        BaseValue = 10 '静的な変数などを初期化
        Console.WriteLine("値型のタイプコンストラクタが呼び出されました。")
    End Sub

    Public Overrides Function ToString() As String
        Return "値は" & (Me.Value + BaseValue).ToString()
    End Function

End Structure

Module Sample

    Sub Main()

        '参照型のタイプコンストラクタ
        Console.WriteLine("参照型のタイプコンストラクタは呼び出されるかな?")
        Dim r As ReferenceType() = New ReferenceType(10) {}
        r(0) = New ReferenceType() 'Nullに初期化されている
        r(0).Value = 10
        Console.WriteLine("参照しなくてもタイプコンストラクタは呼び出さられる。")
        Console.WriteLine(r(0).ToString() & vbNewLine)

        '値型のタイプコンストラクタの挙動は難しいので避けるべき
        Console.WriteLine("値型のタイプコンストラクタは呼び出さられるかな?")
        Dim v As ValueType() = New ValueType(10) {}
        'v(0) = new ValueType( ) '値型は必要ない
        v(0).Value = 100
        Console.WriteLine("あれ?参照してみよう。")
        '値型のタイプコンストラクタ派参照すると呼び出される
        Console.WriteLine(v(0).ToString() & vbNewLine)

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

    End Sub

End Module


文法
 静的指定している点と、アクセス修飾子が指定できず、規定でprivateになる点を除けば、デフォルトコンストラクタと同じ文法です。文法的には似ていますが、全く違う内容を表わしているので十分に注意してください。

解説
 インスタンスではなく、型を対象にした初期化処理が必要な場合があります。例えば、型に属する変数の初期化処理や、環境の準備などが必要な場合、タイプコンストラクタを使用します。インスタンスごとに行う初期化なのか、型に対して行う初期化処理なのかは、十分に設計しておく必要があります。
 注意するべき点は、参照型と値型の挙動が違う点です。参照型と値型はメモリ配置の形式が異なりますので、タイプコンストラクタの実行されるタイミングが異なります。特に値型は参照型よりもルールが複雑なので、極力値型のタイプコンストラクタの定義は避けるべきだと思います。もしどうしても必要ならば、必ず検証作業をしておくべきでしょう。そうしないと、発見困難なエラーに悩まされる羽目になるかもしれません。
スポンサーサイト



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

C#文法リファレンス - タイプコンストラクタ

概要
 型共通の初期化処理を定義します。デフォルトコンストラクタと似ていますが、デフォルトコンストラクタは、インスタンスの初期化ですので違う機能です。

日常でたとえると
 世の中には暗黙の了解というものが沢山あります。それら事前に決まっていることを、プログラムで表現しています。

使用に適した状況
 型に共通して存在する初期化処理が必要な場合。インスタンスごとに必要な処理か、型に必要な処理なのかをよく考えて使い分ける必要があります。

サンプル

/*----------------------------------------------------
 * 
 *  タイプコンストラクタ
 *  
 ----------------------------------------------------*/
using System;

class ReferenceType
{
    public int Value;
    public static int BaseValue;

    static ReferenceType()
    {
        BaseValue = 10;//静的な変数などを初期化
        Console.WriteLine( "参照型のタイプコンストラクタが呼び出されました。" );
    }

    public override string ToString()
    {
        return "値は" + ( this.Value + BaseValue ).ToString();
    }
}

struct ValueType
{
    public int Value;
    public static int BaseValue = 10;

    static ValueType()
    {
        BaseValue = 10;//静的な変数などを初期化
        Console.WriteLine( "値型のタイプコンストラクタが呼び出されました。" );
    }

    public override string ToString()
    {
        return "値は" + ( this.Value + BaseValue ).ToString( );
    }
}

class Sample
{
    static void Main()
    {
        //参照型のタイプコンストラクタ
        Console.WriteLine( "参照型のタイプコンストラクタは呼び出されるかな?" );
        ReferenceType[ ] r = new ReferenceType[ 10 ];
        r[ 0 ] = new ReferenceType( ); //Nullに初期化されている
        r[ 0 ].Value = 10;
        Console.WriteLine( "参照しなくてもタイプコンストラクタは呼び出さられる。" );
        Console.WriteLine( "{0}\n", r[ 0 ].ToString( ) );

        //値型のタイプコンストラクタの挙動は難しいので避けるべき
        Console.WriteLine( "値型のタイプコンストラクタは呼び出さられるかな?" );
        ValueType[ ] v = new ValueType[ 10 ];
        //v[ 0 ] = new ValueType( ); //値型は必要ない
        v[ 0 ].Value = 100;
        Console.WriteLine( "あれ?参照してみよう。" );
        //値型のタイプコンストラクタ派参照すると呼び出される
        Console.WriteLine( "{0}\n", v[ 0 ].ToString( ) );

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


文法
 静的指定している点と、アクセス修飾子が指定できず、規定でprivateになる点を除けば、デフォルトコンストラクタと同じ文法です。文法的には似ていますが、全く違う内容を表わしているので十分に注意してください。

解説
 インスタンスではなく、型を対象にした初期化処理が必要な場合があります。例えば、型に属する変数の初期化処理や、環境の準備などが必要な場合、タイプコンストラクタを使用します。インスタンスごとに行う初期化なのか、型に対して行う初期化処理なのかは、十分に設計しておく必要があります。
 注意するべき点は、参照型と値型の挙動が違う点です。参照型と値型はメモリ配置の形式が異なりますので、タイプコンストラクタの実行されるタイミングが異なります。特に値型は参照型よりもルールが複雑なので、極力値型のタイプコンストラクタの定義は避けるべきだと思います。もしどうしても必要ならば、必ず検証作業をしておくべきでしょう。そうしないと、発見困難なエラーに悩まされる羽目になるかもしれません。

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

VB文法リファレンス - デフォルトコンストラクタ

概要
 インスタンスの初期処理を設定したい場合に使用します。ただし、指定していない場合もコンパイラが自動で生成します。

使用に適した状況
 コンパイラが自動で生成するので、自分の意図を示すために、デフォルトコンストラクタを常に定義する方が良いでしょう。ただし、デフォルトコンストラクタが必要なく、常にコンストラクタで値を指定し、インスタンスを生成する、何らかの制約を持つオブジェクトは別です。そのようなオブジェクトでは、デフォルトコンストラクタを指定しない方が良いでしょう。

サンプル

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

'デフォルトコンストラクタ

'-------------------------------------------------------
Imports System
Imports System.Reflection


Class Sample : End Class
MustInherit Class AbstractClass : End Class
Module StaticClass : End Module

Structure Value : End Structure
Class Foo

    'デフォルトコンストラクタ
    Public Sub New()
        Console.WriteLine("自分で定義したデフォルトコンストラクタを呼び出しました。")
    End Sub

End Class

Structure Bar

    '値型はデフォルトコンストラクタを定義できない
    'Public Sub New()
    '    Console.WriteLine("呼び出されません")
    'End Sub
End Structure

Module Constructor

    Sub Main()

        '何も指定しない場合、デフォルトコンストラクタが自動生成される。
        Console.WriteLine("参照型のデフォルトコンストラクタ")
        PrintInfo(GetType(Sample))
        Console.WriteLine()

        '自分で実装した場合
        Console.WriteLine("自分で用意した参照型のデフォルトコンストラクタ")
        PrintInfo(GetType(Foo))
        Console.WriteLine()

        Dim obj As Foo = New Foo()
        Console.WriteLine()

        '抽象クラスのデフォルトコンストラクタ
        Console.WriteLine("抽象型のデフォルトコンストラクタ")
        PrintInfo(GetType(AbstractClass))
        Console.WriteLine()

        '静的クラスのデフォルトコンストラクタ
        '※静的クラスはデフォルトコンストラクタは存在しない
        Console.WriteLine("静的クラスのデフォルトコンストラクタ")
        PrintInfo(GetType(StaticClass))
        Console.WriteLine()

        '値型
        Console.WriteLine("値型のデフォルトコンストラクタ")
        PrintInfo(GetType(Value))
        Console.WriteLine()

        '終了
        Console.ReadLine()

    End Sub

    Private Sub PrintInfo(ByVal type As Type)
        Dim count As Integer = 0
        For Each info As ConstructorInfo In type.GetConstructors(
            BindingFlags.NonPublic Or BindingFlags.Public Or BindingFlags.Instance)
            Console.WriteLine("アクセス修飾子はPublic?{0}", info.IsPublic)
            Console.WriteLine("アクセス修飾子はProtected?{0}", info.IsFamily)
            Console.WriteLine(info.ToString())
            count += 1
        Next
        If count = 0 Then
            Console.WriteLine("コンストラクタは存在しません。")
        End If
    End Sub

End Module


文法
 引数を受け取らないコンストラクタであり、Newという名前のサブルーチンのような形式です。文法的には簡単ですが、型の種類ごとにルールの細部は異なります。それに加えて、設計レベルから考える必要があります。ずいぶん簡単に見える文法ですが、使いこなすのは結構難しいです。

解説
 オブジェクト指向設計により、オブジェクトの初期処理がある場合デフォルトコンストラクタを使用します。しかしながら、厳密に初期処理を必要としないオブジェクトは存在しません。コンピュータ上で動く以上、メモリ領域の割り当てなどの処理が必要です。ですから、常にコンストラクタで値を指定しなければ、インスタンスを生成できない、ある一定の制約を持つオブジェクト以外に使用します。
 自分で定義しないと、コンパイラが自動でデフォルトコンストラクタを用意してくれますが、それでは定義忘れなのか、意図的なのかがわかりません。従って、制約上必要がないとはっきりしているとき以外は必ず自分で定義しましょう。
 サンプルプログラムで示したように、参照型と値型ではデフォルトコンストラクタの扱いが異なります。値型はデフォルトコンストラクタを定義できません。従って、厳密にインスタンスを制御する必要がある場合は、参照型にする必要があります。
 その他にも、静的クラスや抽象クラスでもデフォルトコンストラクタのルールが異なります。つまり、型の類ごとにルールが異なるのです。発見しにくいエラーの元になるので、十分に気を付けてください。

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

C#文法リファレンス - デフォルトコンストラクタ

概要
 インスタンスの初期処理を設定したい場合に使用します。ただし、指定していない場合もコンパイラが自動で生成します。

日常でたとえると
 世の中には何も言わないときにこうするというルールが沢山あります。もし、全ての物事を細かく指定しないとならないならば、日常生活が困難になります。例えば、ファミリーレストランで、個々の食材の大きさ、料理の温度、担当するコックの名前...など全てを指定せねばならないのであれば、非常に面倒で行くのが嫌になるでしょう。

使用に適した状況
 コンパイラが自動で生成するので、自分の意図を示すために、デフォルトコンストラクタを常に定義する方が良いでしょう。ただし、デフォルトコンストラクタが必要なく、常にコンストラクタで値を指定し、インスタンスを生成する、何らかの制約を持つオブジェクトは別です。そのようなオブジェクトでは、デフォルトコンストラクタを指定しない方が良いでしょう。

サンプル

/*----------------------------------------------------
 * 
 *  デフォルトコンストラクタ
 *  
 ----------------------------------------------------*/
using System;
using System.Reflection;


class Sample { }
abstract class AbstractClass { }
static class StaticClass { }
struct Value { }
class Foo
{
    public Foo()
    {
        Console.WriteLine( "自分で定義したデフォルトコンストラクタを呼び出しました。" );
    }
}

struct Bar
{
    //値型はデフォルトコンストラクタを定義できない
    //public Bar() {}
}

class Constructor
{
    static void Main()
    {
        //何も指定しない場合、デフォルトコンストラクタが自動生成される。
        Console.WriteLine( "参照型のデフォルトコンストラクタ" );
        PrintInfo( typeof( Sample ) );
        Console.WriteLine( );

        //自分で実装した場合
        Console.WriteLine( "自分で用意した参照型のデフォルトコンストラクタ" );
        PrintInfo( typeof( Foo ) );
        Console.WriteLine( );

        Foo obj = new Foo( );
        Console.WriteLine( );

        //抽象クラスのデフォルトコンストラクタ
        Console.WriteLine( "抽象型のデフォルトコンストラクタ" );
        PrintInfo( typeof( AbstractClass ) );
        Console.WriteLine( );

        //静的クラスのデフォルトコンストラクタ
        //※静的クラスはデフォルトコンストラクタは存在しない
        Console.WriteLine( "静的クラスのデフォルトコンストラクタ" );
        PrintInfo( typeof( StaticClass ) );
        Console.WriteLine( );

        //値型
        Console.WriteLine( "値型のデフォルトコンストラクタ" );
        PrintInfo( typeof( Value ) );
        Console.WriteLine( );

        //終了
        Console.ReadLine( );
    }

    private static void PrintInfo( Type type )
    {
        int count = 0;
        foreach ( ConstructorInfo info in type.GetConstructors(
            BindingFlags.NonPublic | BindingFlags.Public |
            BindingFlags.Instance ) ) {
            Console.WriteLine( "アクセス修飾子はPublic?{0}", info.IsPublic );
            Console.WriteLine( "アクセス修飾子はProtected?{0}", info.IsFamily );
            Console.WriteLine( info.ToString( ) );
            ++count;
        }
        if ( count == 0 )
            Console.WriteLine( "コンストラクタは存在しません。" );
    }
}


文法
 引数を受け取らないコンストラクタであり、型名と同名のメソッドのような形式です。文法的には簡単ですが、型の種類ごとにルールの細部は異なります。それに加えて、設計レベルから考える必要があります。ずいぶん簡単に見える文法ですが、使いこなすのは結構難しいです。

解説
 オブジェクト指向設計により、オブジェクトの初期処理がある場合デフォルトコンストラクタを使用します。しかしながら、厳密に初期処理を必要としないオブジェクトは存在しません。コンピュータ上で動く以上、メモリ領域の割り当てなどの処理が必要です。ですから、常にコンストラクタで値を指定しなければ、インスタンスを生成できない、ある一定の制約を持つオブジェクト以外に使用します。
 自分で定義しないと、コンパイラが自動でデフォルトコンストラクタを用意してくれますが、それでは定義忘れなのか、意図的なのかがわかりません。従って、制約上必要がないとはっきりしているとき以外は必ず自分で定義しましょう。
 サンプルプログラムで示したように、参照型と値型ではデフォルトコンストラクタの扱いが異なります。値型はデフォルトコンストラクタを定義できません。従って、厳密にインスタンスを制御する必要がある場合は、参照型にする必要があります。
 その他にも、静的クラスや抽象クラスでもデフォルトコンストラクタのルールが異なります。つまり、型の類ごとにルールが異なるのです。発見しにくいエラーの元になるので、十分に気を付けてください。

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

VB文法リファレンス - コンストラクタ

概要
 簡潔に初期値を待ったインスタンスを生成します。

使用に適した状況
 インスタンスに何らかの初期値を設定したい場合。

サンプル

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

'コンストラクタ

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

Public Class Foo

    'プロパティ
    Public Property Value As Integer

    'コンストラクタ
    Public Sub New(ByVal newValue As Integer)
        If newValue < 0 Then
            Throw New ArgumentException("0以上の値を指定してください。")
        End If
        Me.Value = newValue
    End Sub

End Class

Module Sample

    Sub Main()

        'コンストラクタで初期値を設定する
        Dim value As Integer = 10
        Dim obj As Foo = New Foo(value)
        Console.WriteLine("初期値{0}を指定してインスタンスを作成します。", value)
        Console.WriteLine("インスタンスの値は{0}です。", obj.Value)

        '終了
        Console.ReadLine()
    End Sub

End Module


文法
 コンストラクタは、Newという名前のサブルーチンの形式です。引数を何も指定しないコンストラクタを、デフォルトコンストラクタと呼びます。デフォルトコンストラクタは、コンストラクタと少し内容が異なりますので、デフォルトコンストラクタについては別に紹介します。

解説
 プログラミングをしているとき、何らかの値を持ったインスタンスを作成したい場合が多々あります。コンストラクタがないプログラミング言語は、変数を作成し多直後に、いちいち値を設定するプログラムをセットで書かねばなりませんでした。しかし、そのような定型作業は、面倒かつプログラムの量を無暗に増やし、正しく行わないとエラーを発生させます。そのような、煩雑かつ、エラーの元となる定型作業を簡潔化するために、コンストラクタは存在します。

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

C#文法リファレンス - コンストラクタ

概要
 簡潔に初期値を待ったインスタンスを生成します。

使用に適した状況
 インスタンスに何らかの初期値を設定したい場合。

日常でたとえると
 役所で何かの届け出を出すとき、氏名・住所などの必須事項を記述しないと受け取ってもらえません。これをプログラミングの世界では、コンストラクタと呼びます。

サンプル

/*----------------------------------------------------
 * 
 *  コンストラクタ
 *  
 ----------------------------------------------------*/
using System;

public class Foo
{
    //プロパティ
    public int Value;

    //コンストラクタ
    public Foo( int value )
    {
        if ( value < 0 ) {
            throw new ArgumentException( "0以上の値を指定してください。" );
        }
        this.Value = value;
    }
}
class Sample
{
    public static void Main()
    {
        //コンストラクタで初期値を設定する
        int value = 10;
        Foo obj = new Foo( value );
        Console.WriteLine( "初期値{0}を指定してインスタンスを作成します。", value );
        Console.WriteLine( "インスタンスの値は{0}です。", obj.Value );

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


文法
 コンストラクタは、型名と同じメソッドの形式です。引数を何も指定しないコンストラクタを、デフォルトコンストラクタと呼びます。デフォルトコンストラクタは、コンストラクタと少し内容が異なりますので、デフォルトコンストラクタについては別に紹介します。

解説
 プログラミングをしているとき、何らかの値を持ったインスタンスを作成したい場合が多々あります。コンストラクタがないプログラミング言語は、変数を作成し多直後に、いちいち値を設定するプログラムをセットで書かねばなりませんでした。しかし、そのような定型作業は、面倒かつプログラムの量を無暗に増やし、正しく行わないとエラーを発生させます。そのような、煩雑かつ、エラーの元となる定型作業を簡潔化するために、コンストラクタは存在します。

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

初心者のためのC#プログラミング本格入門120 - 例外処理テストを覚えよう

 この記事は、初心者のためのC#プログラミング本格入門119の続きです。前回は、オーバーロード(多重定義)と、型を活用する技法について解説しました。今回は、新しいテスト方法を解説します。
 現在サンプルプログラムには、1件のエラーがあります。このエラーを解決する方法を考えてみましょう。エラーを解決するにはいくつかのステップを踏みます。
 始に、エラーとは何かについてよく考えます。テストを作る時は、最初はなんとなく作ってよいのですが、最終的には何をテストするものなのかはっきりさせる必要があります。それは、テストを読む側の立場になって考えればわかると思います。何をするのかよくわからないテストからエラーを報告されても、何についてエラーが出たのか、どうすれば解決するのかなどの疑問が湧きあがってしまいます。従ってテストは、テストを受ける立場になって作らねばなりません。エラーを報告しているEnumeratorWhenRemoveElementテストを元に、正しいテストについて考えていきましょう。
 EnumeratorWhenRemoveElementテストは、Enumeratorオブジェクトの挙動をチェックするものです。より具体的に書くと、System.Collections.Generic.IEnumerableインタフェースの実装法を学習するためのものです。ですから、例外が発生することが想定されていません。例外を想定していないので、エラーが発生しているのです。しかしながら、はたして例外が発生することは悪いことなのでしょうか?答えは否です。例外がスローされるべき状況なので、例外がスローされる事を前提にテストを作らねばなりません。この考えは、初心者の方は難しいと思いますので、これから丁寧に説明していきます。
 以前も開設しましたが、System.Collections.Generic.IEnumerableインタフェースのMoveNextメソッドは、変更があったら例外をスローしなくてはなりません。何故ならば、管理している要素に変更があった時、その変更を知らないままに使用しているオブジェクトがあれば、色々な危険を生むからです。具体例を挙げると、あると思っていたデータが処理の途中でなかったり、出力した直後に削除されていたりします。これらの出来事は、人間にとって不自然な出来事なので、プログラムの出力結果に驚いてしまいます。それで、管理するデータが変化したした旨を伝えるために例外をスローするのが望ましいとされています。例外処理は、こういった「想定外」を防ぐための機能なのです。
 そういったことから例外処理は、メソッドのお仕事のうちの1つです。従って、例外処理をスローするべき状況で、正しく例外をスローしているのかチェックするテストが必要です。今回の場合、要素数をチェックするよりも、例外がスローされているのかチェックするテストを考えるのが正解です。これを踏まえて、テストを改善しましょう。

//関係のないプログラムは省略
class SimpleListTest : Test
{
    //要素数が変化した場合例外をスローしなければならない
    private void EnumeratorWhenRemoveElement()
    {
        base.Execute( );

        //任意の要素を準備
        int count = 10;
        for ( int i = 0 ; i < count ; i++ ) {
            this.target.Add( i );
        }

        //Enumerator取得後に1要素を1つ消す
        this.ie = this.target.GetEnumerator( );
        this.target.Remove( );

        //例外が正しくスローされているのかチェック
        System.InvalidOperationException checkException = null;
        try {
         ie.MoveNext( );
        } catch ( System.InvalidOperationException e ) {
            checkException = e;
        }
        if ( checkException == null ) {
            string message = "管理するデータが変更された後に、" +
                "変更前に取得したインスタンスがMoveNextメソッドを呼び出した場合、" +
                "System.InvalidOperationExceptionをスローしてください。";
            throw new TestFail( message );
        }
    }   
}

以上で全てのエラーが解決しました。安心して前に進めます。
 今回紹介したことは、お仕事でプログラミングをしている人ならば知っていて当然の知識なのですが、私は書籍で解説されているのを見たことがありません。そこで、この連載に盛り込むことに決めていました。こういう実務経験者が知っていて当然の知識を解説しなければ、本当の意味でプログラミングを解説したことにならないと私は考えています。ですから私は、新人教育をするときは、必ずこういったことを教えています。初心者の方は、こういった便利で必須のプログラミング知識は習得しておきましょう。、単純な1つの知識が大きな差を生み出します。単純な一つの知識を習得し、大きな利益を生み出そう。

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

VB文法リファレンス ー プロパティ

概要
 データを安全に読み書きするための文法です。読み取り専用、もしくは書き込み専用に設定できます。

使用に適した状況
 ほぼすべての状況。オブジェクト指向プログラミングをする上で、なくてはならない存在です。

サンプル

'----------------------------------------------------
' 
'  プロパティ
'  
'----------------------------------------------------
Imports System
Imports System.Text

Class Sample

    'プロパティ
    Private _value As Integer
    Public Property Value As Integer
        Get
            Return Me._value
        End Get
        Set(value As Integer)
            If value >= 0 Then
                Me._value = value
            Else
                Throw New ArgumentOutOfRangeException("0未満の数値は指定できません。")
            End If
        End Set
    End Property

    '読み取り専用プロパティ
    Private _id As Integer
    Public ReadOnly Property ID As Integer
        Get
            Return Me._id
        End Get
    End Property

    '書きこみ専用プロパティ
    Private _name As String 'フィールド
    Public WriteOnly Property Name As String
        Set(value As String)
            Me._name = Value
        End Set
    End Property

    'アクセス修飾子を変更
    Public Property Zero As Integer
        Get
            Return 0
        End Get
        Private Set(value As Integer)
        End Set
    End Property

    '確認用メソッド
    Public Overrides Function ToString() As String

        'インデクサ以外のプロパティの値を文字列にする
        Dim result As StringBuilder = New StringBuilder()

        result.Append("Value = ")
        result.Append(Me._value)
        result.Append(Environment.NewLine)

        result.Append("ID = ")
        result.Append(Me.ID)
        result.Append(Environment.NewLine)

        result.Append("Name = ")
        result.Append(Me._name)
        result.Append(Environment.NewLine)

        result.Append("Zero = ")
        result.Append(Me.Zero)
        result.Append(Environment.NewLine)

        '生成した文字列を返す
        Return result.ToString()
    End Function
End Class

Module Program

    Sub Main()

        '準備
        Dim obj As Sample = New Sample()

        'プロパティを使用
        Console.WriteLine("変更前の状態・・・")
        Console.WriteLine(obj.ToString())
        obj.Value = 10
        Console.WriteLine("変更後の状態・・・")
        Console.WriteLine(obj.ToString())

        '読み取り専用プロパティを使用
        Console.WriteLine("ID = 0", obj.ID)
        Console.WriteLine()

        '書き込み専用プロパティを使用
        Console.WriteLine("名前を間違った!")
        obj.Name = "山田花子"
        Console.WriteLine(obj.ToString())
        obj.Name = "山田太郎"
        Console.WriteLine(obj.ToString())

        '終了
        Console.ReadLine()
    End Sub

End Module



文法
 文法に難しいところはないのですが、○○ End を多用している点が気になる人が居るかと思います。○○ Endで括るプログラムはコードブロックを表わしています。つまり、データにアクセスするコード群を指定しているのです。コードブロックがわかれば、プロパティのプログラムを問題なく読み書きできます。

解説
 ほとんどのオブジェクトは何らかのデータを持っています。そしてプログラミングでは、データを読み書きするにはプログラムが必要です。それで、プロパティの文法は、データの名前と型、読み取りと書き取りのコードの塊であるコードブロックを指定する形式になっています。単純にデータを読み書きするだけならば、変数に値を設定すればいいという事になりますが、それだけではプログラミングは成り立ちません。データの整合性を常に保ち、データを正しいものに維持する必要があります。
 データを整合性がある状態に保つには、ただ単に変数の値を変えるだけではなく、入力値をチェックするプログラムと、変数を加工して外部に渡す機能が必要になります。それに加えて、アクセスの範囲をチェックする必要があります。その2つの要請をかなえる形で表現したものがプロパティです。アクセスできる範囲をチェックするのは原始的なセキュリティ機能なので、もしかしたらより高度なセキュリティ機能を持つ、新しい文法が将来登場するかもしれません。

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

C#文法リファレンス - プロパティ

概要
 データを安全に読み書きするための文法です。読み取り専用、もしくは書き込み専用に設定できます。

日常でたとえると
 お店で売っている商品の価格は、お客が勝手に変更できません。しかし、経営者や責任者は自由に設定することができます。

使用に適した状況
 ほぼすべての状況。オブジェクト指向プログラミングをする上で、なくてはならない存在です。

サンプル

/*----------------------------------------------------
 * 
 *  プロパティ
 *  
 ----------------------------------------------------*/
using System;
using System.Text;


class Sample
{
    //プロパティ
    private int _value;
    public int Value
    {
        get { return this._value; }
        set
        {
            if ( value >= 0 )
                this._value = value;
            else
                throw new ArgumentOutOfRangeException( "0未満の数値は指定できません。" );
        }
    }

    //読み取り専用プロパティ
    private int _id;
    public int ID
    {
        get { return this._id; }
    }

    //書きこみ専用プロパティ
    private string _name; //フィールド
    public string Name 
    { 
        set { this._name = value; } 
    }

    //アクセス修飾子を変更
    public int Zero
    {
        get { return 0; }
        private set { }
    }

    //確認用メソッド
    public override string ToString()
    {
        //インデクサ以外のプロパティの値を文字列にする
        StringBuilder result = new StringBuilder( );

        result.Append( "Value = " );
        result.Append( this._value );
        result.Append( Environment.NewLine );

        result.Append( "ID = " );
        result.Append( this.ID );
        result.Append( Environment.NewLine );

        result.Append( "Name = " );
        result.Append( this._name );
        result.Append( Environment.NewLine );

        result.Append( "Zero = " );
        result.Append( this.Zero );
        result.Append( Environment.NewLine );

        //生成した文字列を返す
        return result.ToString( );
    }
}

class Property
{
    static void Main()
    {
        //準備
        Sample obj = new Sample( );

        //プロパティを使用
        Console.WriteLine( "変更前の状態・・・" );
        Console.WriteLine( obj.ToString() );
        obj.Value = 10;
        Console.WriteLine( "変更後の状態・・・" );
        Console.WriteLine( obj.ToString( ) );

        //読み取り専用プロパティを使用
        Console.WriteLine( "ID = {0}", obj.ID );
        Console.WriteLine( );

        //書き込み専用プロパティを使用
        Console.WriteLine( "名前を間違った!" );
        obj.Name = "山田花子";
        Console.WriteLine( obj.ToString( ) );
        obj.Name = "山田太郎";
        Console.WriteLine( obj.ToString( ) );

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


文法
 文法に難しいところはないのですが、{}を多用している点が気になる人が居るかと思います。{}で括るプログラムはコードブロックを表わしています。つまり、データにアクセスするコード群を指定しているのです。コードブロックがわかれば、プロパティのプログラムを問題なく読み書きできます。

解説
 ほとんどのオブジェクトは何らかのデータを持っています。そしてプログラミングでは、データを読み書きするにはプログラムが必要です。それで、プロパティの文法は、データの名前と型、読み取りと書き取りのコードの塊であるコードブロックを指定する形式になっています。単純にデータを読み書きするだけならば、変数に値を設定すればいいという事になりますが、それだけではプログラミングは成り立ちません。データの整合性を常に保ち、データを正しいものに維持する必要があります。
 データを整合性がある状態に保つには、ただ単に変数の値を変えるだけではなく、入力値をチェックするプログラムと、変数を加工して外部に渡す機能が必要になります。それに加えて、アクセスの範囲をチェックする必要があります。その2つの要請をかなえる形で表現したものがプロパティです。アクセスできる範囲をチェックするのは原始的なセキュリティ機能なので、もしかしたらより高度なセキュリティ機能を持つ、新しい文法が将来登場するかもしれません。

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

初心者のためのC#プログラミング本格入門119 - オブジェクト指向プログラミングは親をも使う

 この記事は、初心者のためのC#プログラミング本格入門118の続きです。前回は、オブジェクト指向プログラミングを行う際によくある間違いについて解説しました。今回は、オブジェクト指向プログラミングの技法のうちの一つである、オーバーロードと、使用する型の選別法について解説します。
 前回の最後に紹介した冗長なプログラムは、同様のプログラムが2か所あります。重複しているプログラムがあれば、極力1つにするのが鉄則です。何故ならば、重複して存在しているプログラムは、様々な弊害を生むからです。例えば、後で間違っていることに気づいた、やりたい内容が変わったなどといった理由で、プログラムを変更する際に、更新ミスを誘発します。重複して散在するプログラムを、全て正しいものに修正する行為は、煩雑かつ更新忘れの危険が伴います。他にもいくつか理由がありますが、初心者の方が混乱するだけなので、プログラムの重複は悪だと覚えてください。
 話を戻して、先ほどのプログラムの修正方法を考えます。こういった場合、リファクタリングという技法を使い、重複しているプログラムをメソッドにして取り出します。

//関係のないプログラムは省略
abstract class Test
{
    //全てのテストを実行する
    public void ExecuteAllTest()
    {
        string msg;
        System.Action[ ] tests = GetTests();
        foreach ( System.Action test in tests ) {
            try {
                test( );
            } catch ( TestFail e ) {
                this.Error( e );
            } catch ( System.InvalidOperationException e ) {
                this.Error( e );
            }
        }
    }
    
    protected void Error( TestFail e )
    {
        string msg = e.Message +
            System.Environment.NewLine +
            e.StackTrace;
        this.Error( msg );
    }

    protected void Error( System.InvalidOperationException e )
    {
        string msg = e.Message +
            System.Environment.NewLine +
            e.StackTrace;
        this.Error( msg );
    }
}

このプログラムを書き終わったら、一度デバッグ実行(F5)をして、結果が修正前と同様なのか確認してください。プログラムの修正は、このように確認しつつ少しずつ行います。
 同じ名前のメソッドを複数定義している点に注目してください。これは、オーバーロード(多重定義)というものです。オーバーロードは、オブジェクト指向プログラムの原則のうちの一つ、多態性という性質に対応した機能です。これで、ExecuteAllTestメソッドから重複したプログラムが消え、すっきりとしました。しかし、まだ問題が一つあります。それは、全く同じプログラムのオーバーロードメソッドが2つも存在することです。これも重複しているといえます。
 こんな時は、型の継承関係を確認します。具体的には、MSDNや書籍を調べましょう。その型はどのオブジェクトから派生しているか(どのオブジェクトの子か)書かれているはずです。もしそれでもわからない場合は、開発ソフトでF12キーを押してください。そうすればプログラムが読めれば親がわかります。皆様が調べたものとして話しを進めます。
 TestFailオブジェクトと、System.InvalidOperationExceptionオブジェクトの共通した親は、System.Exceptionオブジェクトです。System.InvalidOperationExceptionオブジェクトの直接の親は、SystemExceptionオブジェクトですが、そのまた親はExceptionオブジェクトなので、共通した親はSystem.Exceptionオブジェクトです。従って、System.Exceptionオブジェクトを使ってメソッドを定義します。

//関係のないプログラムは省略
abstract class Test
{
    //全てのテストを実行する
    public void ExecuteAllTest()
    {
        string msg;
        System.Action[ ] tests = GetTests();
        foreach ( System.Action test in tests ) {
            try {
                test( );
            } catch ( TestFail e ) {
                this.Error( e );
            } catch ( System.InvalidOperationException e ) {
                this.Error( e );
            }
        }
    }
    
    //親を使えば1つで済む
    protected void Error( System.Exception e )
    {
        string msg = e.Message +
            System.Environment.NewLine +
            e.StackTrace;
        this.Error( msg );
    }
}

親を使うというと聞こえは悪いですが、プログラミングの親は、血縁関係の親ではないので気にしないでください。
 さて、目ざとく読者は、例外処理を受け取るcatchの部分が同じだと思うかもしれません。ですが、catchステートメントでSystem.Exceptionを受け取るようにしたら駄目です。何故ならば、意図していない例外も飲み込まれるからです。つまり、テストの目的と合致したものと、偶然発生したものの区別がつかなくなるのです。テストをプログラミングする人は、なんとなくエラーがわかればいいという考えでは駄目です。どのような間違いをチェックするテストプログラムなのか、ちゃんと把握してなければ駄目なのです。
 お疲れ様でした。今回ちょっと長くなりましたが、これで終わりです。次回は違う内容を書きます。

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

プロフィール

インドリ

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カウンター