英文:
How to define a type of a bit-combination?
问题
我正在努力使用PowerShell创建一个具有类似文件属性的位组合的自定义类型。稍后,该类型的使用应该像这样工作:
$attr = [myType]::new()
$attr.read = $true
$attr.write = $true
$attr.execute = $true
write-host $attr # 或者 $attr.toString()? -> read,write,execute
write-host $attr.value__ # -> 7 (3位设置为1)
我的最终类型将需要6位。我希望在以后的代码中跳过手动位操作的部分,以便获取每个位。因此,如果可能的话,我希望在类型中实现它。有关如何完成这个任务的任何想法吗?
英文:
I am struggling with Powershell to create a custom type that has a bit-combination like file-attributes. The usage of the type should work later like this:
$attr = [myType]::new()
$attr.read = $true
$attr.write = $true
$attr.execute = $true
write-host $attr # or $attr.toString()? -> read,write,execute
write-host $attr.value__ # -> 7 (3 bits set to 1)
My final type will need 6 bits. I want to skip the part with manual bit-operations in my later code to get each bit back. So, I want to have it in the type, if possible. Any ideas how to get this done?
答案1
得分: 3
为此,您可以使用PowerShell的枚举作为标志功能:
> ## 枚举作为标志
> 枚举可以定义为一组位标志的集合。 在任何给定点,枚举表示这些标志中的一个或多个打开状态。
>
> 要使枚举作为标志正常工作,每个标签应该具有二的幂值。
适用于您问题的示例
在以下示例中创建了Access枚举
[Flags()] enum Access {
Execute = 1
Write = 2
Read = 4
}
利用PowerShell隐式类型转换的优势,其中通常左操作数决定右操作数的类型转换(尊重运算符优先级),您可以如下使用enum
标志:
分配
要向[Access]
类型分配位(标志),您可以使用简单的字符串数组:
$Access = [Access]'Read', 'Execute'
或者由@mklement0评论的,使用单个字符串:
$Access = [Access]'Read, Execute'
阅读
要读取(和/或显示)分配的访问:
$Access
Execute, Read
[int]$Access
5
设置
要设置[Access]
类型的位(标志),您可以使用二进制或(-bor
)运算符:
$Access -bor 'Write'
Execute, Write, Read
重置
要重置[Access]
类型的位(标志),您可以使用二进制与(-band
)和二进制反转器(-bnot
)运算符:
$Access -band -bnot [Access]'Read'
Execute
<sup>(请注意,您需要显式设置-not
运算符的RHS类型)</sup>
测试
要测试特定位是否已设置,可以使用二进制比较运算符-band
。 在此示例中,我们测试$Access
值中的[Access]
属性。
If ($Access -band 'Read') { 'You have read access' }
'You have read access'
如@mclayton所指出,这对于一次多个标志将不起作用:
$Access -band ([Access]'read, write')
Read
返回Read
,它隐式转换为$True
,请参阅:布尔\从集合类型转换。
换句话说,如果您想确保$Access
值中设置了所有相关位(标志),您可能想使用HasFlag
方法:
$Access.HasFlag([Access]'read, write')
False
感谢@mklement0列出了与枚举相关的值得注意的GitHub问题(截至PowerShell 7.4.0-preview.3):
- Bug:枚举类型的参数不适当地接受多个值,即使对于非标志类型
- Bug:定义具有负值的自定义枚举会绕过强制转换/赋值的验证
- 建议:在方法重载解析期间,优先考虑给定字符串参数时的枚举重载
- 建议:为变量分配基于标志的枚举值提供制表符完成
- 建议:自定义类和枚举类型文字未被制表符完成识别
英文:
For this you might use the PowerShell Enumerations as flags feature:
> ## Enumerations as flags
> Enumerations can be defined as a collection of bit flags. Where, at any given point the enumeration represents one or more of those flags turned on.
>
> For enumerations as flags to work properly, each label should have a power of two value.
Example specific to your question
In the following example the Access enumeration is created
[Flags()] enum Access {
Execute = 1
Write = 2
Read = 4
}
Taking advantage of the PowerShell implicit type casting where generally the left-hand-side of the operator dictates the type casting of the right-hand-side (respecting the operator precedence) you might use the flag enum
as follows:
Assigning
To assign bits (flags) to the [Access]
type, you might use a simple string array:
$Access = [Access]'Read', 'Execute'
Or as commented by @mklement0, use a single string:
$Access = [Access]'Read, Execute'
Reading
To read (and/or display) the assigned access:
$Access
Execute, Read
[int]$Access
5
Setting
To set a bit (flag) of the [Access]
type, you might use the binary or (-bor
) operator:
$Access -bor 'Write'
Execute, Write, Read
Resetting
To reset a bit (flag) of the [Access]
type, you might use the binary and (-band
) and a binary invertor (-bnot
) operator:
$Access -band -bnot [Access]'Read'
Execute
<sup>(note that you will need to explicitly set the type for RHS of the -not
operator)</sup>
Testing
To test that a specific bit is set, you can use the binary comparison operator -band
. In this example, we test for the [Access]
attributes in the value of $Access
.
If ($Access -band 'Read') { 'You have read access' }
'You have read access'
As noted by @mclayton this will not work for multiple flags in once:
$Access -band ([Access]'read, write')
Read
Returns Read
which implicitly casts to $True
, see: Booleans\Converting from collection types.
In other words, if you want to make sure that all concerned bits (flags) are set in the $Access
Value, you probably want to use the HasFlag
method instead:
$Access.HasFlag([Access]'read, write')
False
Thank you @mklement0 for the list of notable enum-relevant GitHub issues (as of PowerShell 7.4.0-preview.3):
- Bug: enum-typed parameters inappropriately accept multiple values even for non-flag types
- Bug: Defining a custom enum with a negative value bypasses validation on cast / assignment
- Suggestion: During method overload resolution, give precedence to enum overloads when given string arguments
- Suggestion: Tab completion for assignment of flag-based enum values to variables
- Suggestion: Custom-class and enum type literals are not recognized by tab completion
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论