C# 防止属性序列化

C# 防止属性序列化,c#,vb.net,serialization,C#,Vb.net,Serialization,这比SO上发布的其他类似问题中讨论的直截了当的场景要复杂一些 我有这样一个类的层次结构: DrawingObject(abstract类,定义abstract属性Size和位置) 标签(继承绘图对象。提供了大小和位置的具体实现。这两个属性都应序列化) 行(在序列化/反序列化过程中应忽略继承的绘图对象大小和位置属性) 我正在使用DataContractSerializer序列化我的DrawingObjects,这会造成以下问题: 如果我没有用DataContract标记任何类,Ignor

这比SO上发布的其他类似问题中讨论的直截了当的场景要复杂一些

我有这样一个类的层次结构:

  • DrawingObject
    abstract
    类,定义
    abstract
    属性
    Size
    位置
    • 标签
      (继承
      绘图对象
      。提供了
      大小
      位置
      的具体实现。这两个属性都应序列化)
    • (在序列化/反序列化过程中应忽略继承的
      绘图对象
      大小
      位置
      属性)
我正在使用
DataContractSerializer
序列化我的
DrawingObject
s,这会造成以下问题:

  • 如果我没有用
    DataContract
    标记任何类,
    IgnoreDataMember
    无效,
    位置
    /
    大小
    属性将被序列化为
    标签
    。我不想要的东西
  • 如果我在我的类上应用
    DataContract
    ,会生成一个运行时异常,告诉我
    DrawingObject
    不能用
    DataContract
    标记,因为它的基类
    observegeObject
    (是,MVVM灯)没有用
    DataContract
    属性标记
如何防止这些属性在一个派生类中序列化而不在另一个派生类中序列化

编辑 我挖得越多,就越奇怪。看起来.NET Framework 3.5稍微更改了规则,
[DataContract]
[DataMember]
属性将使
DataContractSerializer
工作。如果省略这些属性,
DataContractSerializer
将序列化该类的所有公共读/写属性(该类必须具有一个无公共参数的构造函数)。对于我的场景来说,这可能是一个好消息,但C#和VB.NET在这方面的表现似乎有点不同:

C# 以下代码正确序列化:

using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;

namespace ConsoleApp1
{
  public abstract class DrawingObject
  {
    public abstract string Location { get; set; }
    public abstract string Size { get; set; }
  }

  public class Label : DrawingObject
  {
    public Label() { }

    private string _Loc;
    private string _Sz;

    public override string Location { get { return _Loc; } set { _Loc = value; } }
    public override string Size { get { return _Sz; } set { _Sz = value; } }
  }

  public class Line : DrawingObject
  {
    public Line() { }

    public override string Location { get { return "Line Location"; } set { Console.WriteLine("Line.Location.set"); } }
    public override string Size { get { return "Line Size"; } set { Console.WriteLine("Line.Size.set"); } }
  }

  class Program
  {
    static void Main(string[] args)
    {
      DrawingObject D1 = new Label() { Location="Label Loc", Size="Label Sz" } ;
      DrawingObject D2 = new Line();

      List<DrawingObject> DObjs = new List<DrawingObject>();
      DObjs.Add(D1);
      DObjs.Add(D2);

      DataContractSerializer S = new DataContractSerializer(typeof(List<DrawingObject>), new[] { typeof(Line), typeof(Label) }, 0x7FFF, false, true, null);

      var sb = new System.Text.StringBuilder();

      using (var writer = new StringWriter(sb))
      {
        using (var xmlWriter = System.Xml.XmlWriter.Create(writer, new System.Xml.XmlWriterSettings() { Indent = true, OmitXmlDeclaration = false }))
          S.WriteObject(xmlWriter, DObjs);

        Console.WriteLine(sb.ToString());

        Console.Read();
      }
    }
  }
}
我试图使它们在语法上等价,但
DataContractSerializer
的行为却不同

编辑2 我测试了@CodeCaster的建议,并将
[IgnoreDataMember]
应用于
对象的
位置
属性。没有任何区别(
位置
属性仍为
序列化)。看起来,
DataContractSerializer
在派生类中不尊重此属性。我还尝试直接序列化行对象,而不是父对象
列表
<代码>位置
甚至会写入输出

不知道从这里到哪里去

编辑3 经过一天的挖掘和尝试,上述c#和VB.NET代码之间的差异最终成为刷新XML编写器的一个问题。奇怪的是,C#代码不要求我在序列化对象后调用
Flush()
,而VB.NET仅在
WriteObject()之后调用
Flush()
时才生成输出

我发现的另一件事是,
IgnoreDataMember
对派生类中被重写的成员没有任何影响。必须在基类中应用该属性才能使其工作,这在我的例子中当然是不可能的。我想我必须发明一些破解方法来解决这个问题。

必须使用“KnownType”才能使DataContractSerializer执行正确的序列化,因此您的基类需要DataContract Atibute并通知子类类型,如示例所示

[DataContract]
[KnownType(typeof(Label))]
public abstract class DrawingObject
{
public abstract string Location { get; set; }
public abstract string Size { get; set; }
}

“如果我没有用DataContract标记任何类,则IgnoreDataMember无效”-t尝试一下。我是在应用
DataContract
之前这样做的<代码>位置
大小
正在写入序列化输出。不应该发生这种情况。请阅读并创建一个“如果我没有用DataContract标记任何类,IgnoreDataMember无效”-您的意思是,您将该属性放在覆盖上?还是基于抽象属性?根据要求,请扩展到a。我仅在派生类上应用
IgnoreDataMember
,显然不在基类中,因为我不希望它在
标签
的情况下忽略这些属性。谢谢。我已经试过了。没什么区别。你成功地完成了吗?
[DataContract]
[KnownType(typeof(Label))]
public abstract class DrawingObject
{
public abstract string Location { get; set; }
public abstract string Size { get; set; }
}