Поделиться через


about_Classes_Constructors

Краткое описание

Описывается определение конструкторов для классов PowerShell.

Подробное описание

Конструкторы позволяют задавать значения по умолчанию и проверять логику объекта в момент создания экземпляра класса . Конструкторы имеют то же имя, что и класс . Конструкторы могут иметь параметры для инициализации элементов данных нового объекта.

Конструкторы классов PowerShell определяются как специальные методы класса . Они ведут себя так же, как методы класса PowerShell со следующими исключениями:

  • Конструкторы не имеют выходного типа. Они не могут использовать return ключевое слово.
  • Конструкторы всегда имеют то же имя, что и класс .
  • Конструкторы нельзя вызывать напрямую. Они выполняются только при создании экземпляра.
  • Конструкторы никогда не отображаются в выходных данных командлета Get-Member .

Дополнительные сведения о методах класса PowerShell см. в разделе about_Classes_Methods.

Класс может иметь ноль или несколько конструкторов. Если конструктор не определен, классу присваивается конструктор без параметров по умолчанию. Этот конструктор инициализирует все члены значениями по умолчанию. Типы объектов и строки получают значения NULL. При определении конструктора не создается конструктор без параметров по умолчанию. Create конструктор без параметров, если он необходим.

Можно также определить статический конструктор без параметров.

Синтаксис

Конструкторы классов используют следующие синтаксисы:

Синтаксис конструктора по умолчанию

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

Синтаксис статического конструктора

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

Синтаксис параметризованного конструктора (однострочный)

<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

Примечание

По умолчанию свойства $nullName и Author имеют значение, так как они вводимы в виде строк, которые являются ссылочным типом. Другие свойства имеют значение по умолчанию для определенного типа, так как они имеют свойства типа значения. Дополнительные сведения о значениях по умолчанию для свойств см. в разделе Значения свойств по умолчанию в about_Classes_Properties.

Пример 2. Переопределение конструктора по умолчанию

ExampleBook2 явно определяет конструктор по умолчанию, устанавливая для значений PublishedOn текущую дату, а pages — значение 1.

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 определяет три перегрузки конструктора, что позволяет пользователям создавать экземпляр класса из хэш-диаграммы, передавая каждое значение свойства и передавая имя книги и автора. Класс не определяет конструктор по умолчанию.

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

MethodException:
Line |
  42 |  [ExampleBook3]::new()
     |  ~~~~~~~~~~~~~~~~~~~~~
     | Cannot find an overload for "new" and the argument count: "0".

Вызов конструктора по умолчанию возвращает исключение метода. Автоматический конструктор по умолчанию определяется только для класса, если класс не определяет конструкторы. Так как 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. Статический конструктор для класса .
  2. Применимая перегрузка конструктора для класса .

Для производных классов, наследующих от другого класса, порядок имеет следующий порядок:

  1. Статический конструктор для базового класса.
  2. Статический конструктор для производного класса.
  3. Если конструктор производного класса явно вызывает перегрузку базового конструктора, он запускает этот конструктор для базового класса. Если он явно не вызывает базовый конструктор, он запускает конструктор по умолчанию для базового класса.
  4. Применимая перегрузка конструктора для производного класса.

Во всех случаях статические конструкторы выполняются только один раз в сеансе.

Пример поведения конструктора и упорядочения см. в примере 5.

Скрытые конструкторы

Конструкторы класса можно скрыть, объявив их с hidden помощью ключевое слово. Скрытые конструкторы классов:

  • Не входит в выходные данные по умолчанию для класса .
  • Не входит в список членов класса, возвращаемых командлетом Get-Member . Чтобы отобразить скрытые свойства с Get-Memberпомощью , используйте параметр Force .
  • Не отображается в завершении табуляции или IntelliSense, если только завершение не происходит в классе, определяющем скрытое свойство.
  • Открытые члены класса . К ней можно обращаться и изменять. Скрытие свойства не делает его частным. Он скрывает только свойство, как описано в предыдущих пунктах.

Примечание

При скрытии конструктора new() параметр удаляется из IntelliSense и результатов завершения.

Дополнительные сведения о ключевое слово см. в hiddenразделе about_Hidden.

Статические конструкторы

Конструктор можно определить как принадлежащий самому классу, а не экземплярам класса, объявив конструктор с static помощью ключевое слово. Конструкторы статических классов:

  • Вызовите только при первом создании экземпляра класса в сеансе.
  • Не может иметь никаких параметров.
  • Не удается получить доступ к свойствам или методам экземпляра с помощью переменной $this .

Конструкторы для производных классов

Когда класс наследуется от другого класса, конструкторы могут вызывать конструктор из базового класса с 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 = @(
        @{
            Name       = '<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 в статическом конструкторе гарантирует, что код для добавления членов в класс должен выполняться только один раз в сеансе.

Добавляйте свойства в класс только в нестатических конструкторах, если их нельзя определить с помощью Update-TypeData, например свойств только для чтения.

Дополнительные сведения об определении методов экземпляра с Update-TypeDataпомощью см. в разделе about_Classes_Methods. Дополнительные сведения об определении свойств экземпляра с помощью Update-TypeDataсм. в разделе about_Classes_Properties.

Ограничения

Конструкторы классов PowerShell имеют следующие ограничения:

  • Цепочка конструкторов не реализована.

    Обходное решение. Определите скрытые Init() методы и вызовите их из конструкторов.

  • Параметры конструктора не могут использовать атрибуты, включая атрибуты проверки.

    Обходной путь. Переназначьте параметры в теле конструктора с помощью атрибута проверки.

  • Параметры конструктора не могут определять значения по умолчанию. Параметры всегда являются обязательными.

    Обходных решений: нет.

  • Если какая-либо перегрузка конструктора скрыта, каждая перегрузка для конструктора также рассматривается как скрытая.

    Обходных решений: нет.

См. также раздел