为何使用Structure而非Class时,设计器不存储DesignTime值?
为何使用Structure而非Class时,设计器不存储DesignTime值?
问题复现代码
<TypeConverter(GetType(ExpandableObjectConverter))> Public Structure ABC Public Property Prop1 As Integer Public Property Prop2 As String Public Property Prop3 As Boolean Public Overrides Function ToString() As String Return Prop2 End Function End Structure <TypeConverter(GetType(ExpandableObjectConverter))> Public Class XYZ Public Property Prop1 As Integer Public Property Prop2 As String Public Property Prop3 As Boolean Public Overrides Function ToString() As String Return Prop2 End Function End Class Public Class MyControl Inherits Control <DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> Public ReadOnly Property ABCs As New ObjectModel.Collection(Of ABC) <DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> Public ReadOnly Property XYZs As New ObjectModel.Collection(Of XYZ) Protected Overrides Sub OnClick(e As EventArgs) For Each a As ABC In ABCs Debug.WriteLine("ABC :" & a.Prop2) Next For Each x As XYZ In XYZs Debug.WriteLine("XYZ :" & x.Prop2) Next End Sub End Class
现象说明
设计器仅生成了XYZs集合的序列化代码,未存储ABCs的值,生成的设计器代码如下:
'MyControl1 ' Me.MyControl1.BackColor = System.Drawing.Color.WhiteSmoke Me.MyControl1.ForeColor = System.Drawing.Color.Gray Me.MyControl1.Location = New System.Drawing.Point(150, 216) Me.MyControl1.Name = "MyControl1" Me.MyControl1.Size = New System.Drawing.Size(182, 123) Me.MyControl1.TabIndex = 2 Me.MyControl1.Text = "MyControl1" Xyz1.Prop1 = 0 Xyz1.Prop2 = "Test" Xyz1.Prop3 = False Me.MyControl1.XYZs.Add(Xyz1)
原因分析
核心差异在于值类型(Structure)和引用类型(Class)的内存模型不同:
XYZ是引用类型,集合中存储的是对象的引用。当你在设计器中修改XYZ的属性时,是直接修改同一个引用指向的对象实例,设计器的序列化机制可以追踪到这个对象内部的属性变更,从而生成对应的序列化代码。ABC是值类型,集合中存储的是它的副本。当你修改ABC的属性时,实际上会创建一个新的ABC实例并替换集合中的旧副本,但设计器默认不会捕捉到这种值类型的替换操作——因为值类型没有引用可以追踪,设计器无法检测到集合元素的变化,也就不会生成序列化代码。
解决方法
如果需要让值类型集合在设计器中被序列化,可以尝试以下方案:
- 将Structure改为Class:这是最简单的方案,直接利用引用类型的序列化特性。
- 自定义序列化逻辑:给
ABC结构添加<Serializable>属性,确保它支持序列化;自定义集合类,重写GetObjectData方法或实现IXmlSerializable接口来手动控制序列化过程。 - 触发集合变更通知:修改
ABC属性后,手动移除旧实例并添加新实例到集合中,强制触发INotifyCollectionChanged事件,让设计器检测到元素变化。
内容的提问来源于stack exchange,提问作者Mo Khalefa
相关产品推荐
相关产品推荐

