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


about_Enum

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

Оператор enum объявляет перечисление . Перечисление — это отдельный тип, состоящий из набора именованных меток, называемых списком перечислителя.

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

Оператор enum позволяет создать строго типизированный набор меток. Это перечисление можно использовать в коде без анализа или проверка для орфографических ошибок.

Перечисления внутренне представлены как целочисленные типы значений с начальным значением 0. По умолчанию перечисления PowerShell используют System.Int32 ([int]) в качестве базового типа. По умолчанию PowerShell назначает первой метке в списке нулевое значение. По умолчанию PowerShell назначает оставшиеся метки с последовательными целыми числами.

В определении можно присвоить меткам любое целочисленное значение. Метки без присвоенного значения принимают следующее целочисленное значение.

Синтаксис

Перечисления используют следующий синтаксис:

Синтаксис определения перечисления integer

[[<attribute>]...] enum <enum-name> {
    <label> [= <int-value>]
    ...
}

Синтаксис определения перечисления конкретных базовых типов

[[<attribute>]...] enum <enum-name> : <underlying-type-name> {
    <label> [= <int-value>]
    ...
}

Синтаксис определения перечисления флагов

[[<attribute>]...] [Flag()] enum <enum-name>[ : <underlying-type-name>] {
    <label 0> [= 1]
    <label 1> [= 2]
    <label 2> [= 4]
    <label 3> [= 8]
    ...
    ...
}

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

[<enum-name>]::<label>

Примеры

Пример 1. Минимальное перечисление

Следующий блок кода определяет перечисление MarkdownUnorderedListCharacter с тремя метками. Он не присваивает явные значения какой-либо метки.

enum MarkdownUnorderedListCharacter {
    Asterisk
    Dash
    Plus
}

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

$ValuesToConvert = @(0, 'Asterisk', 1, 'Dash', 2, 'Plus')
foreach ($Value in $ValuesToConvert) {
    [MarkdownUnorderedListCharacter]$EnumValue = $Value

    [pscustomobject]@{
        AssignedValue = $Value
        Enumeration   = $EnumValue
        AreEqual      = $Value -eq $EnumValue
    }
}
AssignedValue Enumeration AreEqual
------------- ----------- --------
            0    Asterisk     True
     Asterisk    Asterisk     True
            1        Dash     True
         Dash        Dash     True
            2        Plus     True
         Plus        Plus     True

Приведение целых чисел, равных значению перечисления, возвращает это перечисление. Приведение строк, которые совпадают с меткой перечисления, возвращает это перечисление.

Пример 2. Значения явного перечисления и перечисления синонимов

В следующем примере показано перечисление объектов, коррелирующих с файлами мультимедиа. Определение присваивает явные значения базовым значениям music, picture, video. Метки сразу после явного назначения получают следующее целочисленное значение. Синонимы можно создать, назначив то же значение другой метки; см. сконструированные значения для : ogg, oga, moggили jpg, jpegили mpg. mpeg

enum MediaTypes {
    unknown
    music   = 10
    mp3
    aac
    ogg     = 15
    oga     = 15
    mogg    = 15
    picture = 20
    jpg
    jpeg    = 21
    png
    video   = 40
    mpg
    mpeg    = 41
    avi
    m4v
}

Метод GetEnumNames() возвращает список меток для перечисления .

[MediaTypes].GetEnumNames()
unknown
music
mp3
aac
ogg
oga
mogg
picture
jpg
jpeg
png
video
mpg
mpeg
avi
m4v

Метод GetEnumValues() возвращает список значений для перечисления .

[MediaTypes].GetEnumValues()
unknown
music
mp3
aac
ogg
ogg
ogg
picture
jpg
jpg
png
video
mpg
mpg
avi
m4v

Примечание

GetEnumNames() и GetEnumValues() возвращают те же результаты; список именованных значений. Однако внутренне перечисляет значения, GetEnumValues() а затем сопоставляет значения с именами. Внимательно прочтите список, и вы заметите, что ogg, ogaи mogg отображаются в выходных GetEnumNames()данных , но в выходных GetEnumValues() данных отображается oggтолько . То же самое происходит для jpg, jpegи mpg. mpeg Имя, возвращаемое PowerShell для значений синонимов, не является детерминированным.

Метод можно использовать для GetEnumName() получения имени, связанного с определенным значением. Если со значением связано несколько имен, метод возвращает первое определенное имя.

[MediaTypes].GetEnumName(15)
ogg

В следующем примере показано, как сопоставить каждое имя со значением.

[MediaTypes].GetEnumNames() | ForEach-Object {
  [pscustomobject]@{
    Name = $_
    Value = [int]([MediaTypes]::$_)
  }
}
Name    Value
----    -----
unknown     0
music      10
mp3        11
aac        12
ogg        15
oga        15
mogg       15
picture    20
jpg        21
jpeg       21
png        22
video      40
mpg        41
mpeg       41
avi        42
m4v        43

Одно значение перечисления можно указать с помощью его метки с помощью синтаксиса [<enum-name>]::<label>.

[MediaTypes]::png
[MediaTypes]::png -eq 22
png
True

Пример 3. Перечисление в виде флагов

Следующий блок кода создает перечисление FileAttributes в виде набора битовых флагов. Значение каждой метки в два раза превышает значение предыдущей метки.

[Flags()] enum FileAttributes {
    Archive    = 1
    Compressed = 2
    Device     = 4
    Directory  = 8
    Encrypted  = 16
    Hidden     = 32
}

[FileAttributes]$file1 =  [FileAttributes]::Archive
[FileAttributes]$file1 += [FileAttributes]::Compressed
[FileAttributes]$file1 += [FileAttributes]::Device
"file1 attributes are: $file1"

[FileAttributes]$file2 = [FileAttributes]28 ## => 16 + 8 + 4
"file2 attributes are: $file2"
file1 attributes are: Archive, Compressed, Device
file2 attributes are: Device, Directory, Encrypted

Чтобы проверить, установлен ли определенный флаг, можно использовать бинарный оператор -bandсравнения . В этом примере проверяется наличие атрибутов Device и Archive в значении $file2.

PS > ($file2 -band [FileAttributes]::Device) -eq [FileAttributes]::Device
True

PS > ($file2 -band [FileAttributes]::Archive) -eq [FileAttributes]::Archive
False

Вы также можете использовать метод , HasFlag() чтобы проверить, установлен ли определенный флаг. В этом примере выполняется проверка атрибутов Device и Hidden в значении $file1.

PS > $file1.HasFlag([FileAttributes]::Device)
True

PS > $file1.HasFlag([FileAttributes]::Hidden)
False

Пример 4. Перечисление в качестве параметра

В следующем примере функция ConvertTo-LineEndingRegex определяет параметр InputObject с типом EndOfLine.

enum EndOfLine {
    CR   = 1
    LF   = 2
    CRLF = 3
}

function ConvertTo-LineEndingRegex {
    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline)]
        [EndOfLine[]]$InputObject
    )

    process {
        switch ($InputObject) {
            CR   {  '\r'  }
            LF   {  '\n'  }
            CRLF { '\r\n' }
        }
    }
}

[EndOfLine]::CR | ConvertTo-LineEndingRegex

'CRLF' | ConvertTo-LineEndingRegex

ConvertTo-LineEndingRegex 2
\r

\r\n

\n

В этом примере первый оператор, вызывающий ConvertTo-LineEndingRegex , передает значение перечисления для CR. Второй оператор передает строку 'CRLF', которая приводится к LineEnding. Третий оператор задает значение 2 параметра , которое сопоставляется с меткой LF .

Параметры завершения аргументов можно просмотреть, введя следующий текст в командной строке PowerShell:

ConvertTo-LineEndingRegex -InputObject <Tab>

При указании недопустимого имени метки или числового значения для параметра функция выдает ошибку.

ConvertTo-LineEndingRegex -InputObject 0
ConvertTo-LineEndingRegex: Cannot process argument transformation on
parameter 'InputObject'. Cannot convert value "0" to type "EndOfLine" due
to enumeration values that are not valid. Specify one of the following
enumeration values and try again. The possible enumeration values are
"CR,LF,CRLF".

Пример 5. Перечисления с определенными базовыми типами

Начиная с PowerShell 6.2, можно определить перечисления с определенным базовым типом. В этом примере показаны допустимые базовые типы для перечисления.

Первый блок кода инициализирует две переменные как массивы. $EnumTypes — это пустой массив для хранения динамически создаваемых типов. $IntegralTypes — это массив, содержащий допустимые базовые типы для перечисления.

$EnumTypes     = @()
$IntegralTypes = @(
    'byte', 'sbyte', 'short', 'ushort', 'int', 'uint', 'long', 'ulong'
)

Следующий блок кода определяет шаблон для динамического создания определений перечисления. {0} Если заполнитель формата заменяется именем целочисленного типа, шаблон создает блок скрипта, который:

  1. Определяет перечисление с именем <type>Enum, например byteEnum. Определенное перечисление использует указанный целочисленный тип в качестве базового типа значения.

    Перечисление определяется со значением Min , равным минимальному значению целочисленного типа. Он определяет максимальное Max значение для целочисленного типа.

  2. Возвращает только что определенный тип.

$DefinitionTemplate = @"
enum {0}Enum : {0} {{
    Min = [{0}]::MinValue
    Max = [{0}]::MaxValue
}}

[{0}Enum]
"@

Следующий блок кода использует шаблон для создания и вызова scriptblock в текущем область. Он добавляет возвращенные определения типов в $EnumTypes массив.

foreach ($IntegralType in $IntegralTypes) {
    $Definition  = $DefinitionTemplate -f $IntegralType
    $ScriptBlock = [scriptblock]::Create($Definition)
    $EnumTypes  += . $ScriptBlock
}

Последний блок кода выполняет цикл над типами перечисления, используя GetEnumValuesAsUnderlyingType() метод для перечисления значений в качестве базового типа. Цикл создает новый объект для каждого значения, отображая тип перечисления, тип значения, метку и фактическое значение.

foreach ($EnumType in $EnumTypes) {
    $EnumType.GetEnumValuesAsUnderlyingType() | ForEach-Object {
        [pscustomobject]@{
            EnumType  = $EnumType.FullName
            ValueType = $_.GetType().FullName
            Label     = $EnumType.GetEnumName($_)
            Value     = $_
        }
    }
}
EnumType   ValueType     Label                Value
--------   ---------     -----                -----
byteEnum   System.Byte   Min                      0
byteEnum   System.Byte   Max                    255
sbyteEnum  System.SByte  Max                    127
sbyteEnum  System.SByte  Min                   -128
shortEnum  System.Int16  Max                  32767
shortEnum  System.Int16  Min                 -32768
ushortEnum System.UInt16 Min                      0
ushortEnum System.UInt16 Max                  65535
intEnum    System.Int32  Max             2147483647
intEnum    System.Int32  Min            -2147483648
uintEnum   System.UInt32 Min                      0
uintEnum   System.UInt32 Max             4294967295
longEnum   System.Int64  Max    9223372036854775807
longEnum   System.Int64  Min   -9223372036854775808
ulongEnum  System.UInt64 Min                      0
ulongEnum  System.UInt64 Max   18446744073709551615

Методы перечисления

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

Формат

Статический Format() метод возвращает форматированные строковые выходные данные для заданного типа перечисления, значения перечисления и строки форматирования. Выходные данные совпадают с вызовом метода ToString для значения с указанной строкой формата.

Статический метод можно использовать для базового типа класса System.Enum или определенного типа перечисления.

[System.Enum]::format([<enum-name>], <value>, <format-string>)
[<enum-name>]::format([<enum-name>], <value>, <format-string>)

Допустимые строки формата: G или g, D или d, X и xF или f. Дополнительные сведения см. в разделе Строки формата перечисления.

В следующем примере каждая из поддерживаемых строк формата перечисления используется для преобразования каждого значения перечисления TaskState в его строковые представления.

enum TaskState {
    ToDo
    Doing
    Done
}

# String format template for the statements
$Statement = "[System.Enum]::Format([TaskState], {0}, '{1}')"

foreach ($Format in @('G', 'D', 'X', 'F')) {
    $StatementToDo  = $Statement -f 0, $Format
    $StatementDoing = $Statement -f "([TaskState]'Doing')", $Format
    $StatementDone  = $Statement -f '[TaskState]::Done', $Format
    $FormattedToDo  = [System.Enum]::Format(
      [TaskState], 0, $Format
    )
    $FormattedDoing = [System.Enum]::Format(
        [TaskState], ([TaskState]'Doing'), $Format
    )
    $FormattedDone  = [System.Enum]::Format(
      [TaskState], [TaskState]::Done, $Format
    )

    "{0,-62} => {1}" -f $StatementToDo,  $FormattedToDo
    "{0,-62} => {1}" -f $StatementDoing, $FormattedDoing
    "{0,-62} => {1}" -f $StatementDone,  $FormattedDone
}
[System.Enum]::Format([TaskState], 0, 'G')                     => ToDo
[System.Enum]::Format([TaskState], ([TaskState]'Doing'), 'G')  => Doing
[System.Enum]::Format([TaskState], [TaskState]::Done, 'G')     => Done
[System.Enum]::Format([TaskState], 0, 'D')                     => 0
[System.Enum]::Format([TaskState], ([TaskState]'Doing'), 'D')  => 1
[System.Enum]::Format([TaskState], [TaskState]::Done, 'D')     => 2
[System.Enum]::Format([TaskState], 0, 'X')                     => 00000000
[System.Enum]::Format([TaskState], ([TaskState]'Doing'), 'X')  => 00000001
[System.Enum]::Format([TaskState], [TaskState]::Done, 'X')     => 00000002
[System.Enum]::Format([TaskState], 0, 'F')                     => ToDo
[System.Enum]::Format([TaskState], ([TaskState]'Doing'), 'F')  => Doing
[System.Enum]::Format([TaskState], [TaskState]::Done, 'F')     => Done

GetEnumName

Метод GetEnumName() отражения возвращает имя для определенного значения перечисления. Входное значение должно быть допустимым базовым типом перечисления, например целое число или значение перечисления. Если со значением связано несколько имен, метод возвращает первое определенное имя.

[<enum-name>].GetEnumName(<value>)
enum GateState {
    Unknown
    Open
    Opening
    Closing
    Closed
}

foreach ($Value in 0..4) {
    [pscustomobject]@{
      IntegerValue = $Value
      EnumName     = [GateState].GetEnumName($Value)
    }
}
IntegerValue EnumName
------------ --------
           0 Unknown
           1 Open
           2 Opening
           3 Closing
           4 Closed

GetEnumNames

Метод GetEnumNames() отражения возвращает имена для каждого значения перечисления в виде строк. Выходные данные включают синонимы.

[<enum-name>].GetEnumNames()
enum Season {
    Unknown
    Spring
    Summer
    Autumn
    Winter
    Fall   = 3
}

[Season].GetEnumNames()
Unknown
Spring
Summer
Fall
Autumn
Winter

GetEnumUnderlyingType

Метод GetEnumUnderlyingType() отражения возвращает базовый тип для значений перечисления.

[<enum-name>].GetEnumUnderlyingType()
enum IntBasedEnum {
    Zero
    One
    Two
}
enum ShortBasedEnum : short {
    Zero
    One
    Two
}

foreach ($EnumType in @([IntBasedEnum], [ShortBasedEnum])) {
    [pscustomobject]@{
        EnumType = $EnumType
        ValueType = $EnumType.GetEnumUnderlyingType()
    }
}
EnumType       ValueType
--------       ---------
IntBasedEnum   System.Int32
ShortBasedEnum System.Int16

GetEnumValues

Метод GetEnumValues() отражения возвращает каждое определенное значение для перечисления.

[<enum-name>].GetEnumValues()
enum Season {
    Unknown
    Spring
    Summer
    Autumn
    Winter
    Fall   = 3
}

[Season].GetEnumValues()
Unknown
Spring
Summer
Fall
Fall
Winter

GetEnumValuesAsUnderlyingType

Метод GetEnumValuesAsUnderlyingType() отражения возвращает каждое определенное значение для перечисления в качестве базового типа.

[<enum-name>].GetEnumValuesAsUnderlyingType()
enum IntBasedEnum {
    Zero
    One
    Two
}
enum ShortBasedEnum : short {
    Zero
    One
    Two
}

foreach ($EnumType in @([IntBasedEnum], [ShortBasedEnum])) {
    [pscustomobject]@{
        EnumType = $EnumType
        ValueType = $EnumType.GetEnumValuesAsUnderlyingType()[0].GetType()
    }
}
EnumType       ValueType
--------       ---------
IntBasedEnum   System.Int32
ShortBasedEnum System.Int16

HasFlag

Метод HasFlag экземпляра определяет, установлен ли битовый флаг для значения перечисления флагов. Использование этого метода короче и проще для чтения, чем двоичное сравнение и эквивалентность проверка.

<enum-value>.HasFlag(<enum-flag-value>)

В следующем примере определяется перечисление флагов ModuleFeatures и показано, какие флаги имеет значение 39 .

[Flags()] enum ModuleFeatures {
    Commands  = 1
    Classes   = 2
    Enums     = 4
    Types     = 8
    Formats   = 16
    Variables = 32
}

$Features = [ModuleFeatures]39

foreach ($Feature in [ModuleFeatures].GetEnumValues()) {
    "Has flag {0,-12}: {1}" -f "'$Feature'", ($Features.HasFlag($Feature))
}
Has flag 'Commands'  : True
Has flag 'Classes'   : True
Has flag 'Enums'     : True
Has flag 'Types'     : False
Has flag 'Formats'   : False
Has flag 'Variables' : True

IsDefined

Статический IsDefined() метод возвращает значение $true , если входное значение определено для перечисления и в противном случае $false. Используйте этот метод, чтобы проверка, является ли значение допустимым для перечисления без обработки ошибок недопустимых аргументов.

Статический метод можно использовать для базового типа класса System.Enum или определенного типа перечисления.

[System.Enum]::IsDefined([<enum-name>], <value>)
[<enum-name>]::IsDefined([<enum-name>], <value>)
enum Season {
    Unknown
    Spring
    Summer
    Autumn
    Winter
    Fall   = 3
}

foreach ($Value in 0..5) {
    $IsValid   = [Season]::IsDefined([Season], $Value)
    $EnumValue = if ($IsValid) { [Season]$Value }

    [pscustomobject] @{
        InputValue = $Value
        IsValid    = $IsValid
        EnumValue  = $EnumValue
    }
}
InputValue IsValid EnumValue
---------- ------- ---------
         0    True   Unknown
         1    True    Spring
         2    True    Summer
         3    True      Fall
         4    True    Winter
         5   False

ToString

Метод ToString() экземпляра возвращает метку для значения перечисления. Этот метод также является представлением по умолчанию для отображения значения перечисления в качестве выходных данных. При необходимости можно указать строку формата для управления отображением значения. Дополнительные сведения о форматировании см. в разделе Форматирование значений перечисления.

Примечание

Для перечислений, определяющих синонимы для определенного значения, не создавайте код, зависящий от выходных ToString()данных . Метод может возвращать любое допустимое имя для значения.

<enum-value>.ToString([<format-string>])

В следующем примере перечисление Shade определяется с Gray в качестве синонима для Grey. Затем он выводит объекты, которые показывают фактическое значение перечисления, перечисление в виде строки и перечисление в виде целого числа.

enum Shade {
    White
    Grey
    Gray = 1
    Black
}

[Shade].GetEnumValues() | Foreach-Object -Process {
    [pscustomobject]@{
        EnumValue    = $_
        StringValue  = $_.ToString()
        IntegerValue = [int]$_
    }
}
numValue StringValue IntegerValue
--------- ----------- ------------
    White White                  0
     Grey Grey                   1
     Grey Grey                   1
    Black Black                  2

Синонимы значений перечисления

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

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

В следующем блоке кода перечисление Shade определяется с Grey помощью и Gray в качестве синонимов.

enum Shade {
    White
    Grey
    Gray = 1
    Black
}

[Shade]'Grey' -eq [Shade]::Gray
[Shade]::Grey -eq 1
[Shade]'Gray' -eq 1
True
True
True

Перечисления как флаги

Одним из распространенных способов использования перечисления является представление набора взаимоисключающих значений. Например, экземпляр ArrivalStatus может иметь значение Early, OnTime или Late. Значение экземпляра ArrivalStatus не имеет смысла отражать несколько констант перечисления.

Однако в других случаях значение объекта перечисления может включать несколько элементов перечисления, и каждый элемент представляет битовое поле в значении перечисления. С помощью flagsAttribute можно указать, что перечисление состоит из битовых полей в качестве флагов, которые пользователи могут объединять.

Чтобы перечисления в качестве флагов работали правильно, необходимо задать для каждой метки целочисленное значение, равное двум. Если не указать значение для метки, PowerShell установит значение на один выше предыдущей метки.

Вы можете определить значения для часто используемых сочетаний флагов, чтобы пользователям было проще одновременно указать набор флагов. Имя значения должно быть объединенным именам флагов. Целочисленное значение должно быть суммой значений флагов.

Чтобы определить, задан ли определенный флаг для значения, используйте HasFlag() метод для значения или бинарный оператор -bandсравнения .

Пример использования перечислений флагов и проверка, установлен ли флаг, см. в примере 3.

Перечисления в качестве параметров

Можно определить параметры командлета, использующие перечисление в качестве типа. При указании перечисления в качестве типа параметра пользователи получают автоматическое завершение и проверку значения параметра. Завершение аргумента предлагает список допустимых меток для перечисления.

Если параметр имеет в качестве типа перечисление, можно указать любой из:

  • Перечисление, например [<EnumType>]::<Label>
  • Метка для перечисления в виде строки
  • Числовое значение перечисления

Пример, показывающий поведение параметра, типизированного перечислением, см. в примере 4.

Перечисления с определенными базовыми типами

Начиная с PowerShell 6.2, можно определить перечисления с определенным базовым типом. При определении перечисления без определенного базового типа PowerShell создает перечисление с [int] (System.Int32) в качестве базового типа.

Базовым типом перечисления должен быть целочисленный тип. В следующем списке указаны допустимые типы с коротким именем и полным именем типа:

  • byte - System.Byte
  • sbyte - System.SByte
  • short - System.Int16
  • ushort - System.UInt16
  • int - System.Int32
  • uint - System.UInt32
  • long - System.Int64
  • ulong - System.UInt64

Вы можете определить конкретный базовый тип для перечисления как короткое или полное имя типа. Следующие определения функционально идентичны. Отличается только имя, используемое для базового типа.

enum LongValueEnum : long {
    Zero
    One
    Two
}
enum LongValueEnum : System.Int64 {
    Zero
    One
    Two
}

Форматирование значений перечисления

Значения перечисления можно преобразовать в их строковые представления, вызвав статический метод Format , а также перегрузки экземпляра метода ToString . Строку формата можно использовать для управления точным способом представления значения перечисления в виде строки. Дополнительные сведения см. в разделе Строки формата перечисления.

В следующем примере используется каждая из поддерживаемых строк формата перечисления (G или g, D или d, X или x, и F или f ) для преобразования каждого элемента перечисления TaskState в его строковые представления.

enum TaskState {
    ToDo
    Doing
    Done
}

[TaskState].GetEnumValues() | ForEach-Object {
    [pscustomobject]@{
        "ToString('G')" = $_.ToString('G')
        "ToString('D')" = $_.ToString('D')
        "ToString('X')" = $_.ToString('X')
        "ToString('F')" = $_.ToString('F')
    }
}
ToString('G') ToString('D') ToString('X') ToString('F')
------------- ------------- ------------- -------------
ToDo          0             00000000      ToDo
Doing         1             00000001      Doing
Done          2             00000002      Done

В следующем примере строки формата используются для значений перечисления флагов.

[Flags()] enum FlagEnum {
    A = 1
    B = 2
    C = 4
}

$FlagValues = @(
    [FlagEnum]::A                                 # 1
    [FlagEnum]::B                                 # 2
    [FlagEnum]::A + [FlagEnum]::B                 # 3
    [FlagEnum]::C                                 # 4
    [FlagEnum]::C + [FlagEnum]::A                 # 5
    [FlagEnum]::C + [FlagEnum]::B                 # 6
    [FlagEnum]::C + [FlagEnum]::A + [FlagEnum]::B # 7
    [FlagEnum]::C + [FlagEnum]::C                 # 8
)

foreach ($Value in $FlagValues) {
    [pscustomobject]@{
        "ToString('G')" = $Value.ToString('G')
        "ToString('D')" = $Value.ToString('D')
        "ToString('X')" = $Value.ToString('X')
        "ToString('F')" = $Value.ToString('F')
    }
}
ToString('G') ToString('D') ToString('X') ToString('F')
------------- ------------- ------------- -------------
A             1             00000001      A
B             2             00000002      B
A, B          3             00000003      A, B
C             4             00000004      C
A, C          5             00000005      A, C
B, C          6             00000006      B, C
A, B, C       7             00000007      A, B, C
8             8             00000008      8

Обратите внимание, что для перечислений флагов строки формата и F отображают список установленных флагов для значения, G разделенного запятыми. Последнее значение, , не содержит никаких флагов, 8так как на самом деле оно не является допустимым набором флагов. Невозможно объединить флаги перечисления для получения суммы без дублирования хотя бы одного флага 8 .

Определение методов расширения с помощью Update-TypeData

Вы не можете определить методы в объявлении для перечисления. Чтобы расширить функциональность перечисления, можно использовать командлет Update-TypeData для определения ScriptMethod элементов перечисления.

В следующем примере командлет используется Update-TypeData для добавления GetFlags() метода в перечисление флага FileAttributes . Он возвращает массив флагов, установленных для значения .

[Flags()] enum FileAttributes {
    Archive    = 1
    Compressed = 2
    Device     = 4
    Directory  = 8
    Encrypted  = 16
    Hidden     = 32
}

$MemberDefinition = @{
    TypeName   = 'FileAttributes'
    MemberName = 'GetFlags'
    MemberType = 'ScriptMethod'
    Value      = {
        foreach ($Flag in $this.GetType().GetEnumValues()) {
          if ($this.HasFlag($Flag)) { $Flag }
        }
    }
}

Update-TypeData @MemberDefinition

$File = [FileAttributes]28

$File.GetFlags()
Device
Directory
Encrypted

Экспорт перечислений с помощью ускорителей типов

По умолчанию модули PowerShell не экспортируют автоматически классы и перечисления, определенные в PowerShell. Пользовательские типы недоступны за пределами модуля без вызова using module оператора .

Однако если модуль добавляет ускорители типов, эти ускорители сразу же становятся доступны в сеансе после импорта модуля пользователями.

Примечание

При добавлении ускорителей типов в сеанс используется внутренний (не открытый) API. Использование этого API может привести к конфликтам. Описанный ниже шаблон выдает ошибку, если при импорте модуля уже существует ускоритель типов с тем же именем. Он также удаляет ускорители типов при удалении модуля из сеанса.

Этот шаблон гарантирует, что типы будут доступны в сеансе. Это не влияет на IntelliSense или завершение при создании файла скрипта в VS Code. Чтобы получить предложения IntelliSense и завершения для пользовательских типов в VS Code, необходимо добавить using module оператор в начало скрипта.

В следующем шаблоне показано, как зарегистрировать классы и перечисления PowerShell в качестве ускорителей типов в модуле. Добавьте фрагмент кода в модуль корневого скрипта после любых определений типов. Убедитесь, $ExportableTypes что переменная содержит все типы, которые вы хотите сделать доступными для пользователей при импорте модуля. Другой код не требует редактирования.

# Define the types to export with type accelerators.
$ExportableTypes =@(
    [DefinedTypeName]
)
# Get the internal TypeAccelerators class to use its static methods.
$TypeAcceleratorsClass = [psobject].Assembly.GetType(
    'System.Management.Automation.TypeAccelerators'
)
# Ensure none of the types would clobber an existing type accelerator.
# If a type accelerator with the same name exists, throw an exception.
$ExistingTypeAccelerators = $TypeAcceleratorsClass::Get
foreach ($Type in $ExportableTypes) {
    if ($Type.FullName -in $ExistingTypeAccelerators.Keys) {
        $Message = @(
            "Unable to register type accelerator '$($Type.FullName)'"
            'Accelerator already exists.'
        ) -join ' - '

        throw [System.Management.Automation.ErrorRecord]::new(
            [System.InvalidOperationException]::new($Message),
            'TypeAcceleratorAlreadyExists',
            [System.Management.Automation.ErrorCategory]::InvalidOperation,
            $Type.FullName
        )
    }
}
# Add type accelerators for every exportable type.
foreach ($Type in $ExportableTypes) {
    $TypeAcceleratorsClass::Add($Type.FullName, $Type)
}
# Remove type accelerators when the module is removed.
$MyInvocation.MyCommand.ScriptBlock.Module.OnRemove = {
    foreach($Type in $ExportableTypes) {
        $TypeAcceleratorsClass::Remove($Type.FullName)
    }
}.GetNewClosure()

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

Импорт перечислений вручную из модуля PowerShell

Import-Module#requires и инструкция импортирует только функции модуля, псевдонимы и переменные, как определено в модуле. Перечисления не импортируются.

Если модуль определяет классы и перечисления, но не добавляет ускорители типов для этих типов, используйте using module оператор для их импорта.

Инструкция using module импортирует классы и перечисления из корневого модуля (ModuleToProcess) модуля скрипта или двоичного модуля. Он не последовательно импортирует классы, определенные во вложенных модулях, или классы, определенные в скриптах, которые находятся в корневом модуле. Определите классы, которые должны быть доступны пользователям за пределами модуля, непосредственно в корневом модуле.

Дополнительные сведения об инструкции см. в usingразделе about_Using.

Загрузка нового измененного кода во время разработки

Во время разработки модуля скрипта обычно вносятся изменения в код, а затем загружают новую версию модуля с помощью Import-Module параметра Force . Это работает только для изменений функций в корневом модуле. Import-Module не перезагружает вложенные модули. Кроме того, нет способа загрузить обновленные классы.

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

Другой распространенной методикой разработки является разделение кода на разные файлы. Если в одном файле есть функция, которая использует перечисления, определенные в другом модуле, следует использовать инструкцию using module , чтобы убедиться, что функции имеют необходимые определения перечисления.

Ограничения

  • Значения перечисления, определенные в PowerShell, нельзя украсить атрибутами. Вы можете украсить только само объявление перечисления, как с FlagsAttribute для определения перечисления как набора битовых флагов.

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

  • Вы не можете определить методы в определениях перечисления, и PowerShell не поддерживает определение [методов расширения], таких как C#.

    Обходной путь. Используйте командлет Update-TypeData , чтобы определить ScriptMethod элементы для перечисления.