Share via


about_Classes_Constructors

Descripción breve

Describe cómo definir constructores para las clases de PowerShell.

Descripción larga

Los constructores permiten establecer valores predeterminados y validar la lógica de objetos en el momento de crear la instancia de la clase . Los constructores tienen el mismo nombre que la clase . Los constructores pueden tener parámetros para inicializar los miembros de datos del nuevo objeto.

Los constructores de clase de PowerShell se definen como métodos especiales en la clase . Se comportan igual que los métodos de clase de PowerShell con las siguientes excepciones:

  • Los constructores no tienen un tipo de salida. No pueden usar la return palabra clave .
  • Los constructores siempre tienen el mismo nombre que la clase .
  • No se puede llamar directamente a los constructores. Solo se ejecutan cuando se crea una instancia.
  • Los constructores nunca aparecen en la salida del Get-Member cmdlet.

Para obtener más información sobre los métodos de clase de PowerShell, consulte about_Classes_Methods.

La clase puede tener cero o más constructores definidos. Si no se define ningún constructor, la clase recibe un constructor sin parámetros predeterminado. Este constructor inicializa todos los miembros en sus valores predeterminados. Los tipos de objeto y las cadenas reciben valores NULL. Al definir el constructor, no se crea ningún constructor sin parámetros predeterminado. Cree un constructor sin parámetros si se necesita uno.

También puede definir un constructor estático sin parámetros.

Sintaxis

Los constructores de clase usan las sintaxis siguientes:

Sintaxis predeterminada del constructor

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

Sintaxis del constructor estático

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

Sintaxis de constructor con parámetros (una línea)

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

Sintaxis de constructor con parámetros (multilínea)

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

Ejemplos

Ejemplo 1: Definición de una clase con el constructor predeterminado

La clase ExampleBook1 no define un constructor. En su lugar, usa el constructor predeterminado automático.

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

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

Nota:

El valor predeterminado de las propiedades Name y Author es $null porque se escriben como cadenas, que es un tipo de referencia. Las otras propiedades tienen el valor predeterminado para su tipo definido, ya que son propiedades de tipo de valor. Para obtener más información sobre los valores predeterminados de las propiedades, vea "Valores de propiedad predeterminados" en about_Classes_Properties.

Ejemplo 2: Invalidación del constructor predeterminado

ExampleBook2 define explícitamente el constructor predeterminado, estableciendo los valores de PublishedOn en la fecha actual y Pages en 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

Ejemplo 3: Definición de sobrecargas de constructor

La clase ExampleBook3 define tres sobrecargas de constructor, lo que permite a los usuarios crear una instancia de la clase a partir de una tabla hash, pasando cada valor de propiedad y pasando el nombre del libro y el autor. La clase no define el constructor predeterminado.

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".

Al llamar al constructor predeterminado, se devuelve una excepción de método. El constructor predeterminado automático solo se define para una clase cuando la clase no define ningún constructor. Dado que ExampleBook3 define varias sobrecargas, el constructor predeterminado no se agrega automáticamente a la clase .

Ejemplo 4: constructores de encadenamiento con un método compartido

En este ejemplo se muestra cómo se puede escribir código compartido reutilizable para constructores. Las clases de PowerShell no pueden usar el encadenamiento de constructores, por lo que esta clase de ejemplo define un Init() método en su lugar. El método tiene varias sobrecargas. Las sobrecargas con menos parámetros llaman a las sobrecargas más explícitas con valores predeterminados para los parámetros no especificados.

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

Ejemplo 5: constructores de clases derivadas

En los ejemplos siguientes se usan clases que definen los constructores estáticos, predeterminados y con parámetros para una clase base y una clase derivada que hereda de la clase base.

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)
    }
}

En el bloque siguiente se muestra la mensajería detallada para llamar a los constructores de clase base. El mensaje de constructor estático solo se emite la primera vez que se crea una instancia de la clase .

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)

El siguiente bloque muestra la mensajería detallada para llamar a los constructores de clase derivadas en una nueva sesión. La primera vez que se llama a un constructor de clase derivada, se llama a los constructores estáticos de la clase base y a la clase derivada. Esos constructores no se vuelven a llamar en la sesión. Los constructores de la clase base siempre se ejecutan antes de los constructores de la clase derivada.

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)

Orden de ejecución del constructor

Cuando se crea una instancia de una clase, se ejecuta el código de uno o varios constructores.

Para las clases que no heredan de otra clase, el orden es:

  1. Constructor estático de la clase .
  2. Sobrecarga de constructor aplicable para la clase .

Para las clases derivadas que heredan de otra clase, el orden es:

  1. Constructor estático para la clase base.
  2. Constructor estático de la clase derivada.
  3. Si el constructor de clase derivada llama explícitamente a una sobrecarga de constructor base, ejecuta ese constructor para la clase base. Si no llama explícitamente a un constructor base, ejecuta el constructor predeterminado para la clase base.
  4. Sobrecarga del constructor aplicable para la clase derivada.

En todos los casos, los constructores estáticos solo se ejecutan una vez en una sesión.

Para obtener un ejemplo de comportamiento y ordenación del constructor, vea Ejemplo 5.

Constructores ocultos

Puede ocultar constructores de una clase declarandolos con la hidden palabra clave . Los constructores de clases ocultos son:

  • No se incluye en la salida predeterminada de la clase .
  • No se incluye en la lista de miembros de clase devueltos por el Get-Member cmdlet . Para mostrar las propiedades ocultas con Get-Member, use el parámetro Force .
  • No se muestra en la finalización de tabulación o En IntelliSense, a menos que se produzca la finalización en la clase que define la propiedad oculta.
  • Miembros públicos de la clase . Se puede acceder a ellos y modificarlos. Ocultar una propiedad no lo hace privado. Solo oculta la propiedad como se describe en los puntos anteriores.

Nota:

Al ocultar cualquier constructor, la new() opción se quita de IntelliSense y los resultados de finalización.

Para obtener más información sobre la hidden palabra clave , consulte about_Hidden.

Constructores estáticos

Puede definir un constructor como perteneciente a la propia clase en lugar de las instancias de la clase declarando el constructor con la static palabra clave . Constructores de clases estáticas:

  • Invoque solo la primera vez que se cree una instancia de la clase en la sesión.
  • No se pueden tener parámetros.
  • No se puede acceder a las propiedades o métodos de instancia con la $this variable .

Constructores para clases derivadas

Cuando una clase hereda de otra clase, los constructores pueden invocar un constructor de la clase base con la base palabra clave . Si la clase derivada no invoca explícitamente un constructor de la clase base, invoca el constructor predeterminado para la clase base en su lugar.

Para invocar un constructor base no predeterminado, agregue : base(<parameters>) después de los parámetros del constructor y antes del bloque body.

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

Al definir un constructor que llama a un constructor de clase base, los parámetros pueden ser cualquiera de los siguientes elementos:

  • Variable de cualquier parámetro en el constructor de clase derivada.
  • Cualquier valor estático.
  • Cualquier expresión que se evalúe como un valor del tipo de parámetro.

Para obtener un ejemplo de constructores en una clase derivada, vea Ejemplo 5.

Constructores de encadenamiento

A diferencia de C#, los constructores de clase de PowerShell no pueden usar el encadenamiento con la : this(<parameters>) sintaxis . Para reducir la duplicación de código, use un método oculto Init() con varias sobrecargas en el mismo efecto. En el ejemplo 4 se muestra una clase con este patrón.

Adición de propiedades y métodos de instancia con Update-TypeData

Más allá de declarar propiedades y métodos directamente en la definición de clase, puede definir propiedades para instancias de una clase en el constructor estático mediante el Update-TypeData cmdlet .

Use este fragmento de código como punto de partida para el patrón. Reemplace el texto del marcador de posición entre corchetes angulares según sea necesario.

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
        }
    }
}

Sugerencia

El Add-Member cmdlet puede agregar propiedades y métodos a una clase en constructores no estáticos, pero el cmdlet se ejecuta cada vez que se llama al constructor. El uso Update-TypeData de en el constructor estático garantiza que el código para agregar los miembros a la clase solo debe ejecutarse una vez en una sesión.

Agregue solo propiedades a la clase en constructores no estáticos cuando no se puedan definir con Update-TypeData, como las propiedades de solo lectura.

Para obtener más información sobre cómo definir métodos de instancia con Update-TypeData, vea about_Classes_Methods. Para obtener más información sobre cómo definir propiedades de instancia con Update-TypeData, vea about_Classes_Properties.

Limitaciones

Los constructores de clase de PowerShell tienen las siguientes limitaciones:

  • El encadenamiento de constructores no se implementa.

    Solución alternativa: defina métodos ocultos Init() y llámelos desde los constructores.

  • Los parámetros de constructor no pueden usar ningún atributo, incluidos los atributos de validación.

    Solución alternativa: reasignar los parámetros en el cuerpo del constructor con el atributo de validación.

  • Los parámetros del constructor no pueden definir valores predeterminados. Los parámetros siempre son obligatorios.

    Solución alternativa: Ninguna.

  • Si alguna sobrecarga de un constructor está oculta, todas las sobrecargas del constructor también se tratan como ocultas.

    Solución alternativa: Ninguna.

Consulte también