Строго введите свойства настраиваемого объекта PS

Я использовал хэш-таблицы для возврата сложных данных из функций, и это сработало хорошо, но я хотел бы, чтобы ключи были строго типизированы, так как у меня есть логические значения, строки, массивы строк, упорядоченные словари и т. д. в возвращаемых хеш-таблицах. . Итак, учитывая что-то вроде этого

[hashtable]$hashtable = @{
    one = 1
    two = "two"
}

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

[hashtable]$hashtable = @{
    [int]one = 1
    [string]two = "two"
}

Но это неверный код. Поэтому я подумал, что смогу это сделать

[psCustomObject]$object = [psCustomObject]@{
    [int]one = 1
    [string]two = "two"
}

Но это тоже недействительно. Я нахожу это немного уродливым, и это также не работает

$object = New-Object -typeName:PSObject
$object | Add-Member -memberType:int -name:'one' -value:1
$object | Add-Member -memberType:string -name:'two' -value:'two'

Итак, я SOL и нет способа или нет элегантного способа создать пользовательский объект со строго типизированными свойствами?


person Gordon    schedule 11.06.2019    source источник
comment
Возможно, вы ищете DataTable, где вы можете установить, чтобы каждый столбец содержал определенный тип данных?   -  person Theo    schedule 11.06.2019
comment
@ Тео, я не знаком с таблицами данных, но, учитывая, что моя конечная цель - не форматирование для вывода, я думаю, что это не решение. Я хочу, чтобы функция возвращала сложную структуру данных, и я хочу иметь возможность строго типизировать возвращаемый объект, чтобы отлавливать любые ошибки, когда я назначаю неправильный тип данных свойству в функции. Часто полученные данные никогда не будут использоваться ни для чего, кроме условного оператора в вызывающем коде.   -  person Gordon    schedule 11.06.2019
comment
DataTable предназначен не для форматирования вывода, а вместо этого является структурой для хранения данных, как и PSObject. Основное отличие заключается в том, что с DataTable вы определяете строго типизированные типы данных для каждого «поля» (столбца), поэтому он не будет принимать данные любого другого типа. Существует множество примеров того, как его использовать, например, здесь например. Мне кажется, это именно то, что вы хотите.   -  person Theo    schedule 11.06.2019
comment
@Тео; Я вижу сейчас. Похоже, я могу делать то, что хочу, но за счет гораздо более запутанной инициализации, а также ссылок на данные. Я начинаю задаваться вопросом, может быть, причина, по которой вы не можете легко сделать это с хеш-таблицами или PSCustomObject, заключается в том, что большинство людей не думают, что в этом есть необходимость. Это заставляет меня задаться вопросом, плохо ли я структурирую свои функции или просто слишком много беспокоюсь.   -  person Gordon    schedule 11.06.2019


Ответы (1)


Внутри литерала хеш-таблицы вместо этого вам нужно привести тип выражения значения:

PS C:\> $object = [PSCustomObject]@{
    one = [int]1
    two = [string]"two"
}
PS C:\> $object|gm -MemberType NoteProperty

   TypeName: System.Management.Automation.PSCustomObject

Name MemberType   Definition
---- ----------   ----------
one  NoteProperty int one=1
two  NoteProperty string two=two

Это, однако, не помешает кому-либо сохранить нецелое или нестроковое значение в любом из свойств — свойство psobject просто не является строго типизированным.


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

class MyOneTwo
{
    [int]$One
    [string]$Two

    MyOneTwo(){}

    MyOneTwo([int]$one, [string]$two){
        $this.One = $one
        $this.Two = $two
    }
}

# Create instances with ::new(), New-Object or a cast:
$object = [MyOneTwo]::new(1,"2")
$object = New-Object MyOneTwo -Property @{ One = 1; Two = "2" }
$object = [MyOneTwo]@{ One = 1; Two = "2" }
person Mathias R. Jessen    schedule 11.06.2019
comment
что задаст тип, но не сильно. Я всегда мог вернуться позже и присвоить строку первому свойству, например $object.one = [string]'one' - person Gordon; 11.06.2019
comment
@Gordon Это было бы то же самое, если бы вы использовали Add-Member -TypeName - свойства psobject просто не строго типизированы - для этого вам понадобится определение класса - person Mathias R. Jessen; 11.06.2019