Home > Windows にまつわる e.t.c.

超簡単な PowerShell Class の使い方(その6/まとめ)


複数回に分けて書いて見通しが悪くなったのでまとめを書いておきます。

 

Class のざっくり説明

Class は拡張された function で内部に値(プロパティ)を持ち、メソッドで操作が出来ます。

PowerSehll でいつも使っているオブジェクトが自前で作れるようになります。

 

クラスの作成とインスタンス化

こんな感じでクラスを作成して、インスタンス化して使います。

# クラス定義
class TestClass{
    [string] hoge(){
        return "Hello PowerShell Class !!"
    }
}

# インスタンス化
$TestObject = New-Object TestClass

# メソッドの実行
$TestObject.hoge()

 

クラス内のプロパティとメソッドへのアクセス

クラス内のプロパティやメソッドをアクセスする場合は $this を明示的に書きます。

class TestClass
{
    # プロパティ
    [int] $Data

    [int] Add([int]$Indata){

        # プロパティに加算
        $this.Data += $Indata

        return $this.Data
    }

    [int] NewAdd([int]$Indata){

        # Add メソッドを呼ぶ
        $this.Data += $this.Add($Indata)

        return $this.Data
    }
}

[int] $Data2 = 20 のように初期値を設定も可能

 

クラスの外からプロパティへのアクセス

プロパティは class の外からもアクセスできますが、直接更新せず更新用のメソッドを作るのがお勧めです。

class TestClass2
{
    # プロパティ
    [int] $Data

    [int] Add([int]$Indata){
        
        $this.Data += $Indata
        
        return $this.Data
    }
}

# インスタンス化
$TestObject2 = New-Object TestClass2

# 10 を加算
$TestObject2.Add(10)

# プロパティの表示
$TestObject2.Data

 

コンストラクタ

インスタンス化する時に自動的に呼ばれる初期値をセットするメソッドをコンストラクタと呼びます。

コンストラクタを定義する場合は、Class 名と同じ名前のメソッドを作成します。

class TestClass4
{
    # プロパティ
    [int] $Data

    # コンストラクタ(初期値のセットするメソッド)
    TestClass4([int]$Indata){
        
        # プロパティに初期値をセット
        $this.Data = $Indata
    }

    # プロパティに加算して return するメソッド
    [int] Add([int]$Indata){
        
        # プロパティに加算
        $this.Data += $Indata
        
        # プロパティ return
        return $this.Data
    }
}

# インスタンス化(コンストラクタで初期値 10 をセット)
$TestObject4 = New-Object TestClass4(10)

# 20 を加算
$TestObject4.Add(20)

 

オーバーロード

オーバーロードとは、同一名のメソッドを多重定義し、引数の種類に合わせたメソッドを実行させる機能です。

class TestClass11{
    [int] $iData        # int 型プロパティ
    [string] $strData   # string 型プロパティ

    # int 型を受け取るメソッド
    [int] Add ( [int] $Indata ){
        $this.iData += $Indata
        return $this.iData
    }

    # string 型を受け取るメソッド
    # int 型を扱う Add メソッド
    [string] Add ( [string] $Indata ){
        $this.strData += $Indata
        return $this.strData
    }
}

# インスタンス化
$TestObject11 = New-Object TestClass11

# int 型を受け取るメソッドで処理される
$TestObject11.Add(10)
$TestObject11.Add(15)

# string 型を受け取るメソッドで処理される
$TestObject11.Add("This is ")
$TestObject11.Add("string.")

 

コンストラクタのオーバーロード

コンストラクタのオーバーロードすると、初期値をセットするコンストラクタと、初期値をセットしないコンストラクタの両立が出来ます。

class TestClass12{
    [int] $Data

    # 初期値を受け取るコンストラクタ
    TestClass12( [int] $InData ){
        $this.Data = $InData
    }

    # 初期値を受け取らないコンストラクタ
    TestClass12(){
        $this.Data = 0
    }

    # Add メソッド
    [int] Add ( [int] $Indata ){
        $this.Data += $Indata
        return $this.Data
    }
}

# インスタンス化(初期値設定)
$TestObject12 = New-Object TestClass12(10)
$TestObject12.Add(15)

# インスタンス化(初期値なし)
$TestObject13 = New-Object TestClass12
$TestObject13.Add(20)

 

static メソッド

static メソッドは、インスタンス化しなくても使用できるメソッドです。

class TestClass21{
    # 16進に変換するメソッド
    static [string] ToHex ( [int] $Indata ){
        return $Indata.tostring("x")
    }
}

# static メソッドを実行する
[TestClass21]::ToHex(255)

 

static 変数

static 変数は、インスタンス化されたオブジェクト間で共有される変数です。

class TestClass22{
           [int] $Data      # 通常のプロパティ
    static [int] $stData    # static なプロパティ

    # 通常変数へのの Add メソッド
    [int] Add ( [int] $Indata ){
        $this.Data += $Indata
        return $this.Data
    }

    # static 変数への Add メソッド
    [int] StaticAdd ( [int] $Indata ){
        [TestClass22]::stData += $Indata
        return [TestClass22]::stData
    }
}

# インスタンス化
$TestObjectA = New-Object TestClass22

# 通常プロパティを操作するメソッドを実行
$TestObjectA.Add(10)

# static なプロパティを操作するメソッドを実行
$TestObjectA.StaticAdd(15)


# もう一つインスタンス化
$TestObjectB = New-Object TestClass22

# 通常プロパティを操作するメソッド実行
$TestObjectB.Add(10)

# static なプロパティを操作するメソッド実行
$TestObjectB.StaticAdd(15)

 

この状態で static 変数を見ると $TestObjectA の操作結果が $TestObjectB の static 変数に反映されています。

 

継承元のメソッドを呼び出す

元となるクラス(ベースクラス)の機能(メソッド)を呼び出す場合は、継承元のクラス名で this をキャストして呼び出します。

# ベースクラス(元となるクラス)定義
class TestClass30{
    [string] hoge(){
        return "Hello PowerShell Class !!"
    }
}

# サブクラス(継承するクラス)定義
class TestClassMethodAdd : TestClass30 {
    [string] hoge2(){
        $Data = ([TestClass30]$this).hoge()
        $Data += "This is hoge2 !!"
        return $Data
    }
}

# インスタンス化
$TestObject = New-Object TestClassMethodAdd

# メソッドの実行
$TestObject.hoge2()

 

継承とオーバーライド

継承とは、既にある class に手を加えることなく機能の追加/変更ができる仕組みです。

オーバーライドとは元となるクラス(ベースクラス)の機能(メソッド)を、継承するクラス(サブクラス)の同名メソッドで書き換える事です。

オーバーライドされなかったメソッドは、ベースクラスのメソッドがそのまま使われます。

同様の手法でベースクラスのメソッドを利用した新しいメソッドを作ったりたり、新たなプロパティやメソッドを追加する事も出来ます。

# ベースクラスを定義
class TestClass30{
    [string] hoge(){
        return "Hello PowerShell Class !!"
    }
}

# ベースクラスを継承したサブクラスを定義
class TestClass33 : TestClass30 {
    
    [string] $NewString = " This is new hoge too !!"

    # ベースクラスのメソッドを呼んでさらに処理を追加するメソッド
    [string] newhoge(){
        $Result = ([TestClass30]$this).hoge()
        $Data = $Result + $this.NewString
        return $Data
    }
}

 

多段継承時で大元のメソッド呼び出す場合

多段継承時で大元のメソッド呼び出す場合、直接継承している class のメソッドとして呼び出す出来ます。

# 大元クラス
class BaseClass{
    [int] $a = 5

    [int] BaseMethod([int] $input){
        return $this.a + $input
    }
}

# 大元クラスを継承した中間継承クラス
class MiddleClass : BaseClass{

    [int] $b

    [int] MiddleMethod([int] $input){
        return $this.b * $input
    }
}

# 中間継承クラスを継承した末端クラス
class SubClass : MiddleClass{

    [int] SubMethod([int] $input){
        # 大元クラスのメソッドだけど、中間継承クラスのメソッドとして呼び出せる
        [int]$c = ([MiddleClass]$this).BaseMethod( $input ) * 2
        return $c
    }
}

# 中間継承クラスを継承
$TestObject = New-Object SubClass

$TestObject.SubMethod(10)

 

ただし、コンストラクタだけは継承したクラス全てで継承元のコンストラクタをオーバーライド( : base() を呼び出すだけであっても )実装しないと、実行時にエラーになるようです。(コンストラクタ引数の数を変更した場合だけかも?)

 

コンストラクタのオーバーライド

コンストラクタのオーバーライドは、ベースクラスのコンストラクタを表す「base」を使ってこんな感じに書きます。

# コンストラクタ
TestClass35([int]$Indata) : base() {

}

 

実行順番は、ベースクラスのコンストラクタ → サブクラスのコンストラクタの順番になります。

コンストラクタのオーバーライドをする時のミソは

・ベースクラスに対応する全てのコンストラクタ作成
・サブクラスでは : base(引数) でベースクラスのコンストラクタを指定
・サブクラスのコンストラクタに渡された引数がそままま : base(引数) に渡され、ベースクラスのコンストラクタが先に実行される
・ベースクラスの内部データは 「([BaseClassName]$this).Property」 でアクセス

# ベースクラス定義
class TestClass34
{
    # 内部データ
    [int] $Data

    # 初期値ありコンストラクタ(こちらが呼ばれる)
    TestClass34([int]$Indata){

        # 内部データに初期値をセット
        $this.Data = $Indata
    }

    # 初期値なしコンストラクタ
    TestClass34(){

        # 内部データに 0 をセット
        $this.Data = 0
    }

    # 内部データに加算して return するメソッド
    [int] Add([int]$Indata){

        # 内部データに加算
        $this.Data += $Indata

        # 内部データ return
        return $this.Data
    }
}

# サブクラスの定義
class TestClass35 : TestClass34{

    # 引数なしコンストラクタ
    TestClass35() : base() {
    }

    # 引数ありコンストラクタ
    TestClass35([int]$Indata) : base([int]$Indata) {
        # 継承元コンストラクタ処理後にこれが実行される
        ([TestClass34]$this).Data = ([TestClass34]$this).Data + $Indata * 2
    }
}

# インスタンス化(ベースクラスのコントラクタ実行後にサブクラスのコンストラクタが実行される)
$TestObject = New-Object TestClass35(10)

# メソッドの実行(ベースクラスのメソッドを使う)
$TestObject.Add(30)

 

.NET Framework から継承する

.NET Framework クラスを継承することも出来ます。

class TestClass : System.Object{
    [string] hoge(){
        return "Hello PowerShell Class !!"
    }
}

 

アクセス制限

PowerShell 5 では class の外からのアクセス制限は public しかサポートされていません。

アクセス制限 プロパティ メソッド PowerShell 5 でのサポート
public Class 外から RW 可能 Class 外から使用可能
protected Class 内と継承先だけ RW 可能, クラス外からは RO のみ Class 内と継承先だけ使用可能 ×
private Class 内 だけ RW 可能 Class 内だけ使用可能 ×
static インスタンス間共有 インスタンス化しなくても使用可能

 

スコープ

クラスを含めたスコープはこんな感じ

# スクリプト スコープ変数
[int] $ScriptData

# この定義をしてもスクリプトスコープにはならない
# [TestClass] $TestClassObject01
# [TestClass] $Script:TestClassObject02

class TestClass{
    # クラス スコープ プロパティ
    # (public しかサポートしていない PS 5 の仕様のため、実際はスクリプト スコープ プロパティ)
    [int] $ClassData

    # 静的プロパティ
    static [int] $StaticData

    # クラス スコープ メソッド
    # (public しかサポートしていない PS 5 の仕様のため、実際はスクリプト スコープ メソッド)
    [int] hoge(){
        # メソッド スコープ 変数
        [int] $MethodData = 3
        return $MethodData
    }

    # 静的メソッド
    static [string] ToHex ( [int] $Indata ){
        return $Indata.tostring("x")
    }
}

function TestFunction(){
    # ファンクション スコープ 変数
    [int] $FunctionData

    # スクリプト スコープ 変数
    [int] $Script:ScriptData

    # ファンクション スコープ オブジェクト
    $FunctionScopeTestObject = New-Object TestClass

    # スクリプト スコープ オブジェクト
    $Script:ScriptScopeTestObject = New-Object TestClass
}

# スクリプト スコープ オブジェクト
ScriptScopeTestObject2 = New-Object TestClass

これ以外にも PowerSehll の class には機能があるので、詳しくは MS のドキュメントを見てください。

PowerShell クラスを使用したカスタム型の作成Creating Custom Types using PowerShell Classes | Microsoft Docs
https://docs.microsoft.com/ja-jp/powershell/wmf/5.0/class_overview

 

 

関連情報

超簡単な PowerShell Class の使い方(その1)
http://www.vwnet.jp/Windows/PowerShell/2017082001/PSv5Class01.htm

超簡単な PowerShell Class の使い方(その2/オーバーロード)
http://www.vwnet.jp/Windows/PowerShell/2017082101/PSv5Class02.htm

超簡単な PowerShell Class の使い方(その3/static)
http://www.vwnet.jp/Windows/PowerShell/2017082201/PSv5Class03.htm

超簡単な PowerShell Class の使い方(その4/継承)
http://www.vwnet.jp/Windows/PowerShell/2017082301/PSv5Class04.htm

超簡単な PowerShell Class の使い方(その5/スコープ)
http://www.vwnet.jp/Windows/PowerShell/2017082302/PSv5Class05.htm

PowerShell Class
http://www.vwnet.jp/Windows/etc.asp#PowerShell_Class

PowerShell クラスを使用したカスタム型の作成Creating Custom Types using PowerShell Classes | Microsoft Docs
https://docs.microsoft.com/ja-jp/powershell/wmf/5.0/class_overview

 

 

back.gif (1980 バイト)

home.gif (1907 バイト)

Copyright © MURA All rights reserved.