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


about_Enum

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

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

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

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

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

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

Синтаксис

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

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

[[<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, . picturevideo Метки сразу после явного назначения получают следующее целочисленное значение. Синонимы можно создать, назначив одно и то же значение другой метки; см. созданные значения для: ogg, oga, moggили jpgjpeg, или 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() перечисляет значения, а затем сопоставляет значения с именами. Внимательно прочтите список, и вы заметите, что ogaogg, и mogg отображается в выходных GetEnumValues() данныхGetEnumNames(), но выходные данные отображаются 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двоичного сравнения. В этом примере проверяются атрибуты устройства и архива в значении $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]
"@

Следующий блок кода использует шаблон для создания и вызова блока скриптов в текущей области. Он добавляет возвращаемые определения типов в $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 или gD , или dX , или x.F 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>])

В следующем примере перечисление шейдера определяется как 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

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

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

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

Следующий блок кода определяет перечисление шейдера с 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или D g, илиdX, илиxF) f .

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

Обратите внимание, что для перечислений G флагов строки и F строки форматирования отображают список флагов набора для значения, разделенного запятыми. Последнее значение, не выводит никаких флагов, 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 членов перечисления.