about_Classes_Constructors

簡単な説明

PowerShell クラスのコンストラクターを定義する方法について説明します。

詳細な説明

コンストラクターを使用すると、クラスのインスタンスを作成するときに、既定値を設定し、オブジェクト ロジックを検証できます。 コンストラクターの名前はクラスと同じです。 コンストラクターには、新しいオブジェクトのデータ メンバーを初期化するためのパラメーターが含まれる場合があります。

PowerShell クラス コンストラクターは、クラスの特殊なメソッドとして定義されます。 これらは、次の例外を除き、PowerShell クラスメソッドと同じように動作します。

  • コンストラクターには出力型がありません。 キーワード (keyword)をreturn使用することはできません。
  • コンストラクターは常にクラスと同じ名前を持ちます。
  • コンストラクターを直接呼び出すことはできません。 これらは、インスタンスが作成されたときにのみ実行されます。
  • コンストラクターは、コマンドレットの出力には Get-Member 表示されません。

PowerShell クラス メソッドの詳細については、「about_Classes_Methods」を参照してください

クラスには、0 個以上のコンストラクターを定義できます。 コンストラクターが定義されていない場合、クラスには既定のパラメーターなしのコンストラクターが指定されます。 このコンストラクターは、すべてのメンバーを既定値に初期化します。 オブジェクトの型と文字列には null 値が与えられます。 コンストラクターを定義すると、既定のパラメーターなしのコンストラクターは作成されません。 必要に応じて、パラメーターなしのコンストラクターを作成します。

パラメーターなしの 静的コンストラクターを定義することもできます。

構文

クラス コンストラクターでは、次の構文を使用します。

既定のコンストラクター構文

<class-name> () [: base([<params>])] {
    <body>
}

静的コンストラクターの構文

static <class-name> () [: base([<params>])] {
    <body>
}

パラメーター化されたコンストラクター構文 (1 行)

<class-name> ([[<parameter-type>]$<parameter-name>[, [<parameter-type>]$<parameter-name>...]]) [: base([<params>])] {
    <body>
}

パラメーター化されたコンストラクター構文 (複数行)

<class-name> (
    [<parameter-type>]$<parameter-name>[,
    [<parameter-type>]$<parameter-name>...]
) [: base([<params>])] {
    <body>
}

例 1 - 既定のコンストラクターを使用してクラスを定義する

ExampleBook1 クラスはコンストラクターを定義しません。 代わりに、自動既定のコンストラクターが使用されます。

class ExampleBook1 {
    [string]   $Name
    [string]   $Author
    [int]      $Pages
    [datetime] $PublishedOn
}

[ExampleBook1]::new()
Name Author Pages PublishedOn
---- ------ ----- -----------
                0 1/1/0001 12:00:00 AM

Note

Name プロパティと Author プロパティの既定値は$null、参照型である文字列として型指定されているためです。 他のプロパティは、値型プロパティであるため、定義された型の既定値を持っています。 プロパティの既定値の詳細については、about_Classes_Propertiesの「既定のプロパティ値」を参照してください

例 2 - 既定のコンストラクターのオーバーライド

ExampleBook2 では、既定のコンストラクターを明示的に定義し、PublishedOn の値を現在の日付に設定し、Pages1.

class ExampleBook2 {
    [string]   $Name
    [string]   $Author
    [int]      $Pages
    [datetime] $PublishedOn

    ExampleBook2() {
        $this.PublishedOn = (Get-Date).Date
        $this.Pages       = 1
    }
}

[ExampleBook2]::new()
Name Author Pages PublishedOn
---- ------ ----- -----------
                1 11/1/2023 12:00:00 AM

例 3 - コンストラクターのオーバーロードの定義

ExampleBook3 クラスは 3 つのコンストラクター オーバーロードを定義します。これにより、ユーザーはすべてのプロパティ値を渡し、書籍と著者の名前を渡すことによって、ハッシュテーブルからクラスのインスタンスを作成できます。 このクラスでは、既定のコンストラクターは定義されません。

class ExampleBook3 {
    [string]   $Name
    [string]   $Author
    [int]      $Pages
    [datetime] $PublishedOn

    ExampleBook3([hashtable]$Info) {
        switch ($Info.Keys) {
            'Name'        { $this.Name        = $Info.Name }
            'Author'      { $this.Author      = $Info.Author }
            'Pages'       { $this.Pages       = $Info.Pages }
            'PublishedOn' { $this.PublishedOn = $Info.PublishedOn }
        }
    }

    ExampleBook3(
        [string]   $Name,
        [string]   $Author,
        [int]      $Pages,
        [datetime] $PublishedOn
    ) {
        $this.Name        = $Name
        $this.Author      = $Author
        $this.Pages       = $Pages
        $this.PublishedOn = $PublishedOn
    }

    ExampleBook3([string]$Name, [string]$Author) {
        $this.Name   = $Name
        $this.Author = $Author
    }
}

[ExampleBook3]::new(@{
    Name        = 'The Hobbit'
    Author      = 'J.R.R. Tolkien'
    Pages       = 310
    PublishedOn = '1937-09-21'
})
[ExampleBook3]::new('The Hobbit', 'J.R.R. Tolkien', 310, '1937-09-21')
[ExampleBook3]::new('The Hobbit', 'J.R.R. Tolkien')
[ExampleBook3]::new()
Name       Author         Pages PublishedOn
----       ------         ----- -----------
The Hobbit J.R.R. Tolkien   310 9/21/1937 12:00:00 AM
The Hobbit J.R.R. Tolkien   310 9/21/1937 12:00:00 AM
The Hobbit J.R.R. Tolkien     0 1/1/0001 12:00:00 AM

Cannot find an overload for "new" and the argument count: "0".
At C:\code\classes.examples.ps1:42 char:1
+ [ExampleBook3]::new()
+ ~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodException
    + FullyQualifiedErrorId : MethodCountCouldNotFindBes

既定のコンストラクターを呼び出すと、メソッド例外が返されます。 自動既定のコンストラクターは、クラスでコンストラクターが定義されていない場合にのみ定義されます。 ExampleBook3 では複数のオーバーロードが定義されているため、既定のコンストラクターはクラスに自動的に追加されません。

例 4 - 共有メソッドを使用してコンストラクターを連結する

この例では、コンストラクターの再利用可能な共有コードを記述する方法を示します。 PowerShell クラスではコンストラクターチェーンを使用できないため、この例のクラスでは代わりにメソッドを Init() 定義します。 メソッドには複数のオーバーロードがあります。 パラメーターの数が少ないオーバーロードは、指定されていないパラメーターの既定値を使用して、より明示的なオーバーロードを呼び出します。

class ExampleBook4 {
    [string]   $Name
    [string]   $Author
    [datetime] $PublishedOn
    [int]      $Pages

    ExampleBook4() {
        $this.Init()
    }
    ExampleBook4([string]$Name) {
        $this.Init($Name)
    }
    ExampleBook4([string]$Name, [string]$Author) {
        $this.Init($Name, $Author)
    }
    ExampleBook4([string]$Name, [string]$Author, [datetime]$PublishedOn) {
        $this.Init($Name, $Author, $PublishedOn)
    }
    ExampleBook4(
      [string]$Name,
      [string]$Author,
      [datetime]$PublishedOn,
      [int]$Pages
    ) {
        $this.Init($Name, $Author, $PublishedOn, $Pages)
    }

    hidden Init() {
        $this.Init('Unknown')
    }
    hidden Init([string]$Name) {
        $this.Init($Name, 'Unknown')
    }
    hidden Init([string]$Name, [string]$Author) {
        $this.Init($Name, $Author, (Get-Date).Date)
    }
    hidden Init([string]$Name, [string]$Author, [datetime]$PublishedOn) {
        $this.Init($Name, $Author, $PublishedOn, 1)
    }
    hidden Init(
        [string]$Name,
        [string]$Author,
        [datetime]$PublishedOn,
        [int]$Pages
      ) {
        $this.Name        = $Name
        $this.Author      = $Author
        $this.PublishedOn = $PublishedOn
        $this.Pages       = $Pages
    }
}

[ExampleBook4]::new()
[ExampleBook4]::new('The Hobbit')
[ExampleBook4]::new('The Hobbit', 'J.R.R. Tolkien')
[ExampleBook4]::new('The Hobbit', 'J.R.R. Tolkien', (Get-Date '1937-9-21'))
[ExampleBook4]::new(
    'The Hobbit',
    'J.R.R. Tolkien',
    (Get-Date '1937-9-21'),
    310
)
Name       Author         PublishedOn           Pages
----       ------         -----------           -----
Unknown    Unknown        11/1/2023 12:00:00 AM     1
The Hobbit Unknown        11/1/2023 12:00:00 AM     1
The Hobbit J.R.R. Tolkien 11/1/2023 12:00:00 AM     1
The Hobbit J.R.R. Tolkien 9/21/1937 12:00:00 AM     1
The Hobbit J.R.R. Tolkien 9/21/1937 12:00:00 AM   310

例 5 - 派生クラスコンストラクター

次の例では、基底クラスと基底クラスから継承する派生クラスの静的、既定、およびパラメーター化されたコンストラクターを定義するクラスを使用します。

class BaseExample {
    static [void] DefaultMessage([type]$Type) {
        Write-Verbose "[$($Type.Name)] default constructor"
    }

    static [void] StaticMessage([type]$Type) {
        Write-Verbose "[$($Type.Name)] static constructor"
    }

    static [void] ParamMessage([type]$Type, [object]$Value) {
        Write-Verbose "[$($Type.Name)] param constructor ($Value)"
    }

    static BaseExample() { [BaseExample]::StaticMessage([BaseExample])  }
    BaseExample()        { [BaseExample]::DefaultMessage([BaseExample]) }
    BaseExample($Value)  { [BaseExample]::ParamMessage([BaseExample], $Value) }
}

class DerivedExample : BaseExample {
    static DerivedExample() { [BaseExample]::StaticMessage([DerivedExample])  }
           DerivedExample() { [BaseExample]::DefaultMessage([DerivedExample]) }

    DerivedExample([int]$Number) : base($Number) {
        [BaseExample]::ParamMessage([DerivedExample], $Number)
    }
    DerivedExample([string]$String) {
        [BaseExample]::ParamMessage([DerivedExample], $String)
    }
}

次のブロックは、基底クラスコンストラクターを呼び出すための詳細メッセージングを示しています。 静的コンストラクター メッセージは、クラスのインスタンスが初めて作成されたときにのみ出力されます。

PS> $VerbosePreference = 'Continue'
PS> $b = [BaseExample]::new()

VERBOSE: [BaseExample] static constructor
VERBOSE: [BaseExample] default constructor

PS> $b = [BaseExample]::new()

VERBOSE: [BaseExample] default constructor

PS> $b = [BaseExample]::new(1)

VERBOSE: [BaseExample] param constructor (1)

次のブロックは、新しいセッションで派生クラス コンストラクターを呼び出すための詳細メッセージングを示しています。 派生クラス コンストラクターが初めて呼び出されると、基底クラスと派生クラスの静的コンストラクターが呼び出されます。 これらのコンストラクターは、セッションでは再び呼び出されません。 基底クラスのコンストラクターは、派生クラスのコンストラクターの前に常に実行されます。

PS> $VerbosePreference = 'Continue'
PS> $c = [DerivedExample]::new()

VERBOSE: [BaseExample] static constructor
VERBOSE: [DerivedExample] static constructor
VERBOSE: [BaseExample] default constructor
VERBOSE: [DerivedExample] default constructor

PS> $c = [DerivedExample]::new()

VERBOSE: [BaseExample] default constructor
VERBOSE: [DerivedExample] default constructor

PS> $c = [DerivedExample]::new(1)

VERBOSE: [BaseExample] param constructor (1)
VERBOSE: [DerivedExample] param constructor (1)

PS> $c = [DerivedExample]::new('foo')

VERBOSE: [BaseExample] default constructor
VERBOSE: [DerivedExample] param constructor (foo)

コンストラクターの実行順序

クラスがインスタンス化されると、1 つ以上のコンストラクターのコードが実行されます。

別のクラスから継承されないクラスの場合、順序は次のようになります。

  1. クラスの静的コンストラクター。
  2. クラスに適用可能なコンストラクター オーバーロード。

別のクラスから継承する派生クラスの場合、順序は次のようになります。

  1. 基底クラスの静的コンストラクター。
  2. 派生クラスの静的コンストラクター。
  3. 派生クラス コンストラクターが基底コンストラクターのオーバーロードを明示的に呼び出すと、基底クラスのコンストラクターが実行されます。 基底コンストラクターを明示的に呼び出さない場合は、基底クラスの既定のコンストラクターが実行されます。
  4. 派生クラスに適用できるコンストラクター オーバーロード。

いずれの場合も、静的コンストラクターはセッションで 1 回だけ実行されます。

コンストラクターの動作と順序の例については、例 5 を参照してください

非表示のコンストラクター

クラスのコンストラクターは、キーワード (keyword)でhidden宣言することで非表示にすることができます。 非表示のクラス コンストラクターは次のとおりです。

  • クラスの既定の出力には含まれません。
  • コマンドレットによって返されるクラス メンバーの一覧には Get-Member 含まれません。 非表示のプロパティをGet-Member表示するには、Force パラメーターを使用します。
  • 非表示のプロパティを定義するクラスで入力候補が発生しない限り、タブ補完または IntelliSense には表示されません。
  • クラスのパブリック メンバー。 アクセスして変更できます。 プロパティを非表示にしても、プライベートにはなりません。 前のポイントで説明したように、プロパティのみが非表示になります。

Note

コンストラクターを非表示にすると、IntelliSense と入力候補の new() 結果からオプションが削除されます。

キーワード (keyword)のhidden詳細については、「about_Hidden」を参照してください

静的コンストラクター

キーワード (keyword)を使用してコンストラクターを宣言することで、クラスのインスタンスではなく、クラス自体に属するコンストラクターとしてコンストラクターをstatic定義できます。 静的クラス コンストラクター:

  • クラスのインスタンスがセッションで初めて作成されたときにのみ呼び出します。
  • パラメーターを指定できません。
  • 変数を使用してインスタンスのプロパティまたはメソッドに $this アクセスできません。

派生クラスのコンストラクター

クラスが別のクラスから継承されると、コンストラクターは基底クラスから キーワード (keyword) を使用してコンストラクターをbase呼び出すことができます。 派生クラスが基底クラスからコンストラクターを明示的に呼び出さない場合は、代わりに基底クラスの既定のコンストラクターが呼び出されます。

既定以外の基本コンストラクターを呼び出すには、コンストラクター パラメーターの後と本文ブロックの前に追加 : base(<parameters>) します。

class <derived-class> : <base-class> {
    <derived-class>(<derived-parameters>) : <base-class>(<base-parameters>) {
        # initialization code
    }
}

基底クラスのコンストラクターを呼び出すコンストラクターを定義する場合、パラメーターには次のいずれかの項目を指定できます。

  • 派生クラス コンストラクターの任意のパラメーターの変数。
  • 任意の静的値。
  • パラメーター型の値に評価されるすべての式。

派生クラスのコンストラクターの例については、例 5 を参照してください

コンストラクターのチェーン

C# とは異なり、PowerShell クラスのコンストラクターは構文で : this(<parameters>) チェーンを使用できません。 コードの重複を減らすには、同じ効果を持つ複数のオーバーロードを含む非表示 Init() のメソッドを使用します。 例 4 は、このパターンを使用するクラスを示しています。

Update-TypeData を使用したインスタンスのプロパティとメソッドの追加

クラス定義でプロパティとメソッドを直接宣言するだけでなく、コマンドレットを使用して静的コンストラクター内のクラスのインスタンスのプロパティを Update-TypeData 定義できます。

このスニペットは、パターンの開始点として使用します。 必要に応じて、山かっこ内のプレースホルダー テキストを置き換えます。

class <class-name> {
    static [hashtable[]] $MemberDefinitions = @(
        @{
            MemberName = '<member-name>'
            MemberType = '<member-type>'
            Value      = <member-definition>
        }
    )

    static <class-name>() {
        $TypeName = [<class-name>].Name
        foreach ($Definition in [<class-name>]::MemberDefinitions) {
            Update-TypeData -TypeName $TypeName @Definition
        }
    }
}

ヒント

このコマンドレットは Add-Member 、非静的コンストラクターのクラスにプロパティとメソッドを追加できますが、このコマンドレットはコンストラクターが呼び出されるたびに実行されます。 静的コンストラクターで使用すると Update-TypeData 、クラスにメンバーを追加するためのコードは、セッションで 1 回だけ実行する必要があります。

読み取り専用プロパティのように、非静的コンストラクターで定義 Update-TypeDataできない場合にのみ、クラスにプロパティを追加します。

インスタンス メソッドUpdate-TypeDataの定義の詳細については、about_Classes_Methodsを参照してください。 インスタンス プロパティUpdate-TypeDataの定義の詳細については、about_Classes_Propertiesを参照してください

制限事項

PowerShell クラスコンストラクターには、次の制限があります。

  • コンストラクターのチェーンは実装されていません。

    回避策: 非表示 Init() のメソッドを定義し、コンストラクター内から呼び出します。

  • コンストラクター パラメーターでは、検証属性を含む属性を使用できません。

    回避策: コンストラクター本体のパラメーターを検証属性で再割り当てします。

  • コンストラクター パラメーターでは既定値を定義できません。 パラメーターは常に必須です。

    回避策: なし。

  • コンストラクターのオーバーロードが非表示の場合、コンストラクターのすべてのオーバーロードも非表示として扱われます。

    回避策: なし。

関連項目