2007/11/28 水曜日

新しいクラスを作る(3) ― コンストラクタ

Filed under: Powershell — flamework @ 19:28:09

コンストラクタの定義

コンストラクタは、次のようなコマンドで定義します。 Constructor <パラメータリスト> <実装> <パラメータリスト>は、Type 型の配列で、<実装>はスクリプトブロックです。実際に作ってみましょう。

PS> New-Class Class3 {
>>     Constructor ([string]) {
>>         $args[0].Message = $args[1]
>>     }
>>     Field public string Message
>> }
>>
NameSpace Name BaseType
----------- ---- ----------
  Class3 System.Object

Class3 は、string 型のパブリックフィールド「Message」を持ち、そのコンストラクタは、string 型の引数を受け取って、それを Message に代入します。ここで、$args[0] には、このクラスによって作られるオブジェクトのインスタンスが代入されており、$args[1..] には、コンストラクタに渡される引数が代入されています。今回の場合、引数は一つだけですので、$args.Length は 2 です。 試してみましょう。

PS> $o = New-Object Class3('Hello World!')
PS> $o.Message
Hello World!

ちゃんと Message に「Hello World!」が代入されています。

Private なフィールドへのアクセス

New-Class.ps1 は、PowerShell でクラスを記述しやすくするために、コンストラクタやメソッドなどをスクリプトブロックで実装する仕様になっています。 すると、ここに一つ問題点が出てきます。それは、PowerShell のスクリプトブロックというのは、あくまでオブジェクトから見れば「よそ者」であるということです。したがって、Private なメンバにシームレスにアクセスすることができません。例えば、次のようにコンストラクタ中で Private なフィールドへ値を代入しようとすると、エラーが発生します。

PS> New-Class Class4 {
>>     Constructor ([string]) {
>>         $args[0].Message = $args[1]
>>     }
>>     Field private string Message
>> }
>>
NameSpace Name BaseType
--------- ---- --------
  Class4 System.Object

PS> $o = New-Object Class4('Hello World!')
New-Object : "1" 個の引数を指定して ".ctor" を呼び出し中に例外が発生しました: "このオブジェクトにプロパティ 'Message' が見つかりません。プロパティが存在し、設定可能なことを確認してください。" 発生場所 行:1 文字:16 + $o = New-Object <<<< Class4('Hello World!')

そのため、次のような冗長な書き方をしなくてはなりません。

PS> New-Class Class5 {
>>     Constructor ([string]) {
>>         $args[0].GetType().GetField('Message', ('NonPublic', 'Instance')).SetValue($args[0], $args[1])
>>     }
>>     Field private string Message
>> }
>>
NameSpace Name BaseType
--------- ---- --------
  Class5 System.Object
PS> $o = New-Object Class5('Hello World!')
PS> $o.GetType().GetField('Message', ('NonPublic', 'Instance')).GetValue($o)
Hello World!

何かいい方法がないか模索中です。

複数のコンストラクタ

コンストラクタはもちろん複数作ることができます。次の例の Class6 は 3 通りの方法でインスタンス化できます。引数が必要ない時、「Constructor {}」としたくなりますが、「Constructor @() {}」と、空の配列を渡すのを忘れないようにしてください。

PS> $c = New-Class Class6 {
>>     Constructor @() {}
>>     Constructor ([string]) {}
>>     Constructor ([string], [int]) {}
>> }
>>
PS> $o = New-Object $c
PS> $o = New-Object $c('Hello World!')
PS> $o = New-Object $c('Hello World!', 100)

2007/11/27 火曜日

新しいクラスを作る(2) ― フィールド

Filed under: Powershell — flamework @ 18:23:16

概要

前回の 新しいクラスを作る(1)でご紹介した New-Class.ps1を使って、フィールドを持つクラスを作ってみます。

フィールドの実装

新しいクラス「Class1」を作成し、string 型のパブリックフィールド「Message」を実装してみましょう。

PS> New-Class Class1 {Field public string Message}
NameSpace Name BaseType
----------- ---- ----------
  Class1 System.Object

オブジェクトを作って Get-Member に渡してみます。

PS> $o = New-Object Class1
PS> $o | Get-Member
 
TypeName: Class1
 
Name MemberType Definition
---- ---------- ----------
Equals Method System.Boolean Equals(Object obj)
GetHashCode Method System.Int32 GetHashCode()
GetType Method System.Type GetType()
ToString Method System.String ToString()
Message Property System.String Message {get;set;}

確かに「Message」というメンバが増えています。「Property」と表示されていますが、これは PowerShell での表示上の問題です。別の方法で確かめてみましょう。

PS> [Class1].GetProperties()
PS> [Class1].GetFields()
System.String Message

GetProperties() では何も表示されませんが、GetFields() で「System.String Message」と表示され、確かにフィールドであることがわかります。 実際に使ってみましょう。

PS> $o.Message = 'Hello World!'
PS> $o.Message
Hello World!

Field コマンドの解説と静的メンバの実装

クラスメンバは、スクリプトブロックの中にコマンドを記述することで定義します。上記では、「Field public string Message」というコマンドを与え、フィールドを実装しました。まず、「Field」というのが、「フィールドを作成する」というコマンドです。続く「public」「string」「Message」が、その引数で、それぞれ「属性」「型」「名前」をあらわします。 属性は、「public」の他に、「private」「static」が使えます。属性を 2 つ以上使いたい場合には、「('public', 'static')」のように、文字列の配列にして渡します。 それでは、Message フィールドを静的フィールドにしてみましょう。

PS> New-Class Class2 {Field ('public', 'static') string Message}
NameSpace Name BaseType
----------- ---- ----------
  Class2 System.Object

試してみます。

PS> [Class2]::Message = 'Hello World!'
PS> [Class2]::Message
Hello World!

これでフィールドが作れるようになりました。

« 前ページへ次ページへ »

Copyright © flamework.net 2008.