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


about_Classes_Constructors

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

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

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

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

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

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

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

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

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

Синтаксис

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

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

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

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

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

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

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

Синтаксис параметризованного конструктора (multiline)

<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

Примечание.

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

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

ExampleBook2 явно определяет конструктор по умолчанию, задав значения для PublishedOn на текущую дату и страницы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, используйте параметр Force .
  • Не отображается в завершении вкладки или IntelliSense, если только не выполняется завершение в классе, определяющем скрытое свойство.
  • Открытые члены класса. К ней можно обращаться и изменять. Скрытие свойства не делает его частным. Он скрывает только свойство, как описано в предыдущих точках.

Примечание.

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

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

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

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

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

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

Когда класс наследует от другого класса, конструкторы могут вызывать конструктор из базового класса с base помощью ключевое слово. Если производный класс явно не вызывает конструктор из базового класса, он вызывает конструктор по умолчанию для базового класса.

Чтобы вызвать неdefault 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() методы и вызовите их из конструкторов.

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

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

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

    Обходной путь: нет.

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

    Обходной путь: нет.

См. также