C# 难以在Winforms和.net中持久化在设计时引用内部属性的集合

C# 难以在Winforms和.net中持久化在设计时引用内部属性的集合,c#,.net,vb.net,winforms,serialization,C#,.net,Vb.net,Winforms,Serialization,解释此问题的最简单方法是向您展示一些代码: Public Interface IAmAnnoyed End Interface Public Class IAmAnnoyedCollection Inherits ObjectModel.Collection(Of IAmAnnoyed) End Class Public Class Anger Implements IAmAnnoyed End Class Public Class MyButton Inherit

解释此问题的最简单方法是向您展示一些代码:

Public Interface IAmAnnoyed
End Interface

Public Class IAmAnnoyedCollection
    Inherits ObjectModel.Collection(Of IAmAnnoyed)
End Class

Public Class Anger
    Implements IAmAnnoyed
End Class

Public Class MyButton
    Inherits Button

Private _Annoyance As IAmAnnoyedCollection
<DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> _
Public ReadOnly Property Annoyance() As IAmAnnoyedCollection
    Get
        Return _Annoyance
    End Get
End Property

Private _InternalAnger As Anger
<DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> _
Public ReadOnly Property InternalAnger() As Anger
    Get
        Return Me._InternalAnger
    End Get
End Property

Public Sub New()
    Me._Annoyance = New IAmAnnoyedCollection
    Me._InternalAnger = New Anger
    Me._Annoyance.Add(Me._InternalAnger)
End Sub

End Class
我在上面添加了一条注释,以说明代码应该如何生成。现在,如果我放弃了界面,只是收集了一些愤怒,那么它就会正确地持续下去

有什么想法吗

更新1 我受够了。这个问题是关于持久化接口集合的,但现在进一步测试它对正常集合不起作用。下面是一些更简单的代码:

Public Class Anger
End Class

Public Class MyButton
    Inherits Button

Private _Annoyance As List(Of Anger)
<DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> _
Public ReadOnly Property Annoyance() As List(Of Anger)
    Get
        Return _Annoyance
    End Get
End Property

Private _InternalAnger As Anger
<DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> _
Public ReadOnly Property InternalAnger() As Anger
    Get
        Return Me._InternalAnger
    End Get
End Property

Public Sub New()
    Me._Annoyance = New List(Of Anger)
    Me._InternalAnger = New Anger
    Me._Annoyance.Add(Me._InternalAnger)
End Sub

End Class
公众阶级愤怒
末级
公共类MyButton
继承按钮
私人烦恼列表(愤怒)
_
公共只读属性烦扰()作为列表(愤怒)
得到
返回烦恼
结束
端属性
私下里,愤怒就是愤怒
_
公共只读属性InternalAnger()作为Anger
得到
还给我
结束
端属性
公共分新()
我。_烦恼=新列表(愤怒)
我。内在愤怒=新的愤怒
我。\你的烦恼。加上(我。\你内心的愤怒)
端接头
末级
设计人员以与原始问题相同的方式修改持久性代码

更新2 我已经搞清楚发生了什么事。我想知道为什么有时它会起作用,而其他的却不起作用。它归结为我为内部属性和集合指定的名称

如果我将属性'Hatterance'重命名为'WTF',它将正确序列化,因为'WTF'按字母顺序在集合名称之后-'InternalAnger'

看起来序列化程序正在按字母顺序创建对象实例,需要在创建集合时创建我的内部属性

我可以通过重命名来修复这个问题,但这是一个黑客行为,我担心编写自定义序列化程序是一项艰巨的工作——这是我以前从未做过的

有什么想法吗

更新3
我已经用一句俏皮话回答了这个问题。除非MS改变codedom序列化设计器代码的方式,否则我对它相当有信心。

我在这里有点不熟悉,但是您不应该在这个只读属性上有一个私有setter吗?我的意思是,它无法序列化它无法设置的内容,对吗?

这里的问题可能是您正在向控件的构造函数中的集合添加一个项,然后设计器将其单独序列化


我认为你评论的“应该已经生成”代码也是不正确的。既然控件的构造函数将InternalAnger添加到集合中,为什么还要在InitializeComponent中看到它

DesignerSerializationVisibility.Content
InternalAnger
属性中移除,它应该可以正常工作

例如(C#但想法是一样的)


我想这就是你想要的。

正如我在OP中所说的,问题归结为我给内部属性和集合起的名字

在不深入研究自定义codedom序列化程序的情况下,简单的解决方案是确保内部属性的名称按字母顺序排在引用它的任何其他属性之前

我通过保留原始属性名“InternalProperty”来实现这一点,但我禁用了序列化,并将其引用到一个代理属性,该属性的名称巧妙,并且已序列化

Private _InternalProperty
Public ReadOnly Property InternalProperty
    Get
        Return Me._ProxyInternalProperty 
    End Get
End Property

<Browsable(False), EditorBrowsable(Never), DesignerSerializationVisibility(Content)> _
Public ReadOnly Property _ProxyInternalProperty
    Get
        Return Me._InternalProperty
    End Get
End Property
Private\u内部属性
公共只读属性InternalProperty
得到
返回我。\u ProxyInternalProperty
结束
端属性
_
公共只读属性\u ProxyInternalProperty
得到
还给我
结束
端属性

这是一个黑客行为,但它比将我的财产重命名为内部财产要好。此外,用户永远不会看到_ProxyInternalProperty,因为它是隐藏的,即使他们发现了它,引用它也没有危险。

只读属性在构造函数中初始化。它不需要setter,只需使用常用的Add和Remove方法将元素添加到setter中或从中删除。这不是问题,它仍然应该正确地序列化它,我只是为了方便而将它放在那里。不管怎样,我已经找出了问题所在,但我不知道如何解决。请参阅我的问题以进行编辑。您好,InternalAnger必须附加DesignerSerializationVisibility.Content,因为它是只读属性,否则您的解决方案将正常工作。我已经弄清楚了正在发生什么-请参阅OP以获取编辑。
public partial class UserControl1 : UserControl
{
    public UserControl1()
    {
        InitializeComponent();
        this.InternalAnger = new Anger();
        this.InternalAnger.SomeValue = 2;
        this.Angers.Add(this.InternalAnger);
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public List<Anger> Angers
    {
        get { return this.list; }
    }

    public Anger InternalAnger { get; set; }

    private List<Anger> list = new List<Anger>();
    private Anger _InternalAnger;
}

public class Anger
{
    public Anger() { }

    public int SomeValue { get; set; }
}
WindowsFormsApplication1.Anger anger1 = new WindowsFormsApplication1.Anger();
anger1.SomeValue = 2;
this.userControl11.Angers.Add(anger1);
this.userControl11.InternalAnger = anger1;
Private _InternalProperty
Public ReadOnly Property InternalProperty
    Get
        Return Me._ProxyInternalProperty 
    End Get
End Property

<Browsable(False), EditorBrowsable(Never), DesignerSerializationVisibility(Content)> _
Public ReadOnly Property _ProxyInternalProperty
    Get
        Return Me._InternalProperty
    End Get
End Property