您可以通过 Struct's/Class 的构造函数命名属性吗?

Can you name properties through a Struct's/Class's constructor?

我已经就此主题进行了一些研究,但并没有真正找到太多相关内容。事实上,我很确定我已经知道这个问题的答案,但我还是要问,以防万一有一些我不知道的高级技术。 (有相当高的概率)你能声明结构的名称吗?s/class 的属性或至少通过某种构造函数重命名它们?

基本上,长话短说,我正在尝试创建一个联合结构,它可以有效地为您提供位域样式标志,但使您能够在声明时为标志指定名称,以使代码看起来更简洁。我知道您在 C 语言中做同样的事情,将一个整数 (char/double/whatever) 和一个位域结构结合起来。我基本上可以做到这一点:

    Public status as BitField({"PowerOn","Ready","Error",...})

基本结构如下:

    Public Structure (or Class) BitField
        Private _value as UInt16

        Public Property value as UInt16
            Get
                Return _value
            End Get
            Set(input as UInt16)
                _value = input
            End Set
        End Property

        Public Property bit0 As Boolean
            Get
                Return ((_value And &H1UI) > 0)
            End Get
            Set(input as Boolean)
                If input Then
                    _value = _value Or &H1UI
                Else
                    _value = _value And &HFFFEUI
                End If
            End Set
        End Property

     (and so on for bit 1 through 15)

        Public Sub New(ByVal names() As String)
            ...Something that redeclairs/renames/equates "bit0" with names(0)...

            ...Something that redeclairs/renames/equates "bit1" with names(1)...
            and so on

        End Sub
    End Structure/Class

然后我可以调用 status.Error 来获取或设置第三位,但如果我愿意,我可以将 status.value 与掩码进行比较以检查特定状态。

我的意思是我知道在 C 中你会这样做:

    union {
        unsigned int value;
        struct {
            unsigned PowerOn:1;
            unsigned Ready:1;
            unsigned Error:1;
            ...
        };
    } status;

但我想在我的代码中获得相同级别的 "cleanliness",而不必有一个巨大的声明,每次我想使用它时都必须复制并重写一半。

就像我一开始说的,我假设我偏离了基地并且没有办法做我在 VB.Net 中提出的建议,但如果有人有任何想法,我'我很想听他们说。

您不能在运行时创建或重命名属性,因为编译器需要知道它们是什么。根据评论,这是一种使用最少的新代码:

为每个 创建具有不同含义或映射的不同 BitSetter 对象的方法
Public Class BitSetter(Of T)
    Private value As UInt16
    Public Sub New(v As UInt16)
        value = v
    End Sub

    Public Sub SetBit(n As T, b As Boolean)
        ' do stuff
    End Sub

    Public Function GetBit(n As T) As Boolean
        ' do stuff
    End Function
End Class
  • 我不确定 Boolean input 参数的原因是什么,但为了清楚起见,我会把它分解成它自己的方法。
  • 如图所示,基值只能在创建新对象时赋值。这可能是也可能不是一个好主意。 SetValue(n As UInt16) 方法是另一种设置方法。
  • 开启Option Strictvalue = value Or &H1UI 等代码包含隐式转换,无法编译。

使 class 通用 (Of T) 将允许您为每个变体定义一组不同的语义:

Private Enum FooBits
    Flag
    [Error]
    Green
    '...
End Enum

Private Enum BarBits
    Red = 0
    Charm = 1
    Quark = 3
    Ziggy = 4
End Enum

如果您不知道,Flag 将用于 Bit(0),Error 将用于 1 等,所以请按顺序进行或明确说明。第二组为它们提供了明确的值,而不是定义不应使用的 [Reserved] 之类的东西,它只是跳过该值,因此 cant 无法使用。创建和使用它们:

' starting value of 3:
Dim fooB As New BitSetter(Of FooBits)(3)
Dim barB As New BitSetter(Of BarBits)(6)       ' value = 6

Dim b As Boolean
b = fooB.GetBit(FooBits.Error)

barB.SetBit(BarBits.Quark, True)

FooBits 版本将只允许 FooBits Enum 的成员与其方法一起使用。 Type 是强制执行的,并且在代码中很清楚正在使用 bit/item。尝试将 BarBits 的成员与 fooB 一起使用(使用 Option Strict)将导致编译错误。它还会阻止传递一个幻数值:

barB.SetBit(2, True)

因此,对于每个新部件或地图,您唯一需要的新代码是新的 Enum 集(和 BitSetter 实例)。

如果你想让它更简洁(例如 b = barB.Get(BarBits.Ziggy)),你需要转义 class 中的方法名称,因为它们是关键字:

Public Sub [Set](n As T, b As Boolean)

Public Function [Get](n As T) As Boolean