过时的属性导致属性被 XmlSerialization 忽略

发布于 2024-07-09 11:16:57 字数 996 浏览 6 评论 0原文

我正在重构一些序列化为 XML 的对象,但需要保留一些属性以实现向后兼容性,我有一种方法可以将旧对象转换为新对象,并清空过时的属性。 我想使用 Obsolete 属性告诉其他开发人员不要使用此属性,但它会导致该属性被 XmlSerializer 忽略。

类似代码:

[Serializable]
public class MySerializableObject
{
    private MyObject _oldObject;
    private MyObject _anotherOldObject;

    private MyObject _newBetterObject;

    [Obsolete("Use new properties in NewBetterObject to prevent duplication")]
    public MyObject OldObject
    {
      get { return _oldObject; }
      set { _oldObject = value; }
    }

    [Obsolete("Use new properties in NewBetterObject to prevent duplication")]
    public MyObject AnotherOldObject
    {
      get { return _anotherOldObject; }
      set { _anotherOldObject = value; }
    }

    public MyObject NewBetterObject
    {
      get { return _anotherOldObject; }
      set { _anotherOldObject = value; }
    } 
}

关于解决方法有什么想法吗? 我最好的解决方案是在 XML 注释中写入过时的内容...

更新:我正在使用 .NET 2.0

I'm refactoring some objects that are serialized to XML but need to keep a few properties for backwards compatibility, I've got a method that converts the old object into the new one for me and nulls the obsolete property. I want to use the Obsolete attribute to tell other developers not to use this property but it is causing the property to be ignored by the XmlSerializer.

Similar Code:

[Serializable]
public class MySerializableObject
{
    private MyObject _oldObject;
    private MyObject _anotherOldObject;

    private MyObject _newBetterObject;

    [Obsolete("Use new properties in NewBetterObject to prevent duplication")]
    public MyObject OldObject
    {
      get { return _oldObject; }
      set { _oldObject = value; }
    }

    [Obsolete("Use new properties in NewBetterObject to prevent duplication")]
    public MyObject AnotherOldObject
    {
      get { return _anotherOldObject; }
      set { _anotherOldObject = value; }
    }

    public MyObject NewBetterObject
    {
      get { return _anotherOldObject; }
      set { _anotherOldObject = value; }
    } 
}

Any ideas on a workaround? My best solution is to write obsolete in the XML comments...

Update: I'm using .NET 2.0

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

小忆控 2024-07-16 11:16:57

编辑阅读后在 MS Connect 文章 中,.Net 2.0 似乎有一个“功能”,它使 ObsoleteAttribute 等同于 XmlIgnoreAttribute,而文档中没有任何通知。 因此,我将修改我的答案,说在这种情况下鱼与熊掌兼得的唯一方法是遵循@Will 的建议和 手动实现序列化。 这将是您在 XML 中包含过时属性的唯一面向未来的方法。 .Net 2.0 并不漂亮,但 .Net 3.0+ 可以让生活变得更轻松。

来自 XmlSerializer

标有“过时属性”的对象不再序列化
在 .NET Framework 3.5 中,XmlSerializer 类不再序列化标记为 [Obsolete] 的对象。

EDIT: After reading a MS Connect article, it appears that .Net 2.0 has a 'feature' where it makes ObsoleteAttribute equivalent to XmlIgnoreAttribute without any notification in the documentation. So I'm going to revise my answer to say that the only way to have your cake and eat it too in this instance is to follow @Will's advice and implement serialization manually. This will be your only future proof way of including Obsolete properties in your XML. It is not pretty in .Net 2.0, but .Net 3.0+ can make life easier.

From XmlSerializer:

Objects marked with the Obsolete Attribute no longer serialized
In the .NET Framework 3.5 the XmlSerializer class no longer serializes objects that are marked as [Obsolete].

月下凄凉 2024-07-16 11:16:57

另一种解决方法是在为数据类型创建序列化程序时订阅 XmlSerializer.UnknownElement,然后以这种方式修复旧数据。

http://weblogs .asp.net/psteele/archive/2011/01/31/xml-serialization-and-the-obsolete-attribute.aspx

也许考虑将订阅方法作为数据类型类的静态方法。

static void serializer_UnknownElement(object sender, XmlElementEventArgs e)
{
    if( e.Element.Name != "Hobbies")
    {
        return;
    }

    var target = (MyData) e.ObjectBeingDeserialized;
    foreach(XmlElement hobby in e.Element.ChildNodes)
    {
        target.Hobbies.Add(hobby.InnerText);
        target.HobbyData.Add(new Hobby{Name = hobby.InnerText});
    }
}

Another workaround is to subscribe to XmlSerializer.UnknownElement, when creating the serializer for the datatype, and then fix old data that way.

http://weblogs.asp.net/psteele/archive/2011/01/31/xml-serialization-and-the-obsolete-attribute.aspx

Maybe consider to have the method for subscribing as a static method on the class for datatype.

static void serializer_UnknownElement(object sender, XmlElementEventArgs e)
{
    if( e.Element.Name != "Hobbies")
    {
        return;
    }

    var target = (MyData) e.ObjectBeingDeserialized;
    foreach(XmlElement hobby in e.Element.ChildNodes)
    {
        target.Hobbies.Add(hobby.InnerText);
        target.HobbyData.Add(new Hobby{Name = hobby.InnerText});
    }
}
别理我 2024-07-16 11:16:57

我一直在努力解决这个问题 - 除了手动进行序列化或使用另一个序列化程序之外,没有其他解决方案。

但是,您可以考虑在属性名称中添加 Obsolete 前缀(例如,Foo 变为 ObsoleteFoo),而不是为每个过时的属性编写填充程序(这很快就会变得很麻烦) code>。这不会像属性那样生成编译器警告,但至少它在代码中可见。

I have struggled with this a lot - there is no solution other than doing serialization manually or using another serializer.

However, instead of writing shims for each obsolete property which quickly becomes a pain, you could consider adding an Obsolete prefix to property names (e.g. Foo becomes ObsoleteFoo. This will not generate a compiler warning like the attribute will, but at least it's visible in code.

计㈡愣 2024-07-16 11:16:57

我最近遇到了与您描述的完全相同的场景。 经过一些挖掘,我发现可以使用 XmlAttributeOverrides,这样您就可以告诉序列化器不要忽略给定的属性。

var overrides = new XmlAttributeOverrides();
var attributes = new XmlAttributes { XmlIgnore = false };
overrides.Add(typeof(MyClass), nameof(MyClass.MyObsoleteProperty), attributes);

var serializer = new XmlSerializer(typeof(MyClass), overrides);

这是一个演示这种方法的小提琴

如果需要的话,这甚至可以扩展为使用反射来查找和“取消忽略”所有Obsolete属性。

I recently came across the exact same scenario as you're describing. Doing some digging, I found out that it's possible to override how a given property is serialized with XmlAttributeOverrides, and with this you can tell the serializer to not ignore a given property.

var overrides = new XmlAttributeOverrides();
var attributes = new XmlAttributes { XmlIgnore = false };
overrides.Add(typeof(MyClass), nameof(MyClass.MyObsoleteProperty), attributes);

var serializer = new XmlSerializer(typeof(MyClass), overrides);

Here's a fiddle demonstrating this approach.

This could potentially even be extended to use reflection to find and 'un-ignore' all Obsolete properties if needed.

你没皮卡萌 2024-07-16 11:16:57

1)WAG:尝试将XmlAttributeAttribute添加到属性中; 也许这会覆盖 ObsoleteAttribute
2) PITA:实现 IXmlSerialized

1) WAG: Try adding the XmlAttributeAttribute to the property; perhaps this will override the ObsoleteAttribute
2) PITA: Implement IXmlSerializable

禾厶谷欠 2024-07-16 11:16:57

是的,我同意用名称“已过时”标记事物,我们使用枚举值来做到这一点

/// <summary>
/// Determines the swap file location for a cluster.
/// </summary>
/// <remarks>This enum contains the original text based values for backwards compatibility with versions previous to "8.1".</remarks>
public enum VMwareClusterSwapFileLocation
{

    /// <summary>
    /// The swap file location is unknown.
    /// </summary>
    Unknown = 0,

    /// <summary>
    /// The swap file is stored in the virtual machine directory.
    /// </summary>
    VmDirectory = 1,

    /// <summary>
    /// The swap file is stored in the datastore specified by the host.
    /// </summary>
    HostLocal = 2,

    /// <summary>
    /// The swap file is stored in the virtual machine directory. This value is obsolete and used for backwards compatibility.
    /// </summary>
    [XmlElement("vmDirectory")]
    ObseleteVmDirectory = 3,

    /// <summary>
    /// The swap file is stored in the datastore specified by the host. This value is obsolete and used for backwards compatibility.
    /// </summary>
    [XmlElement("hostLocal")]
    ObseleteHostLocal = 4,




}

Yes I agree with marking things with the name "Obsolete" we do this with Enum values

/// <summary>
/// Determines the swap file location for a cluster.
/// </summary>
/// <remarks>This enum contains the original text based values for backwards compatibility with versions previous to "8.1".</remarks>
public enum VMwareClusterSwapFileLocation
{

    /// <summary>
    /// The swap file location is unknown.
    /// </summary>
    Unknown = 0,

    /// <summary>
    /// The swap file is stored in the virtual machine directory.
    /// </summary>
    VmDirectory = 1,

    /// <summary>
    /// The swap file is stored in the datastore specified by the host.
    /// </summary>
    HostLocal = 2,

    /// <summary>
    /// The swap file is stored in the virtual machine directory. This value is obsolete and used for backwards compatibility.
    /// </summary>
    [XmlElement("vmDirectory")]
    ObseleteVmDirectory = 3,

    /// <summary>
    /// The swap file is stored in the datastore specified by the host. This value is obsolete and used for backwards compatibility.
    /// </summary>
    [XmlElement("hostLocal")]
    ObseleteHostLocal = 4,




}
甚是思念 2024-07-16 11:16:57

您可以尝试以下解决方法:

添加名为 this 的方法

ShouldSerializeOldObject ()
{
   return true;
}

ShouldSerializeAnotherOldObject ()
{
   return true
}

可能会覆盖过时的属性

You may try the following workaround:

add a method named

ShouldSerializeOldObject ()
{
   return true;
}

ShouldSerializeAnotherOldObject ()
{
   return true
}

this may override the obsolete Attribute

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文