确定在运行时序列化哪些属性

时间:2012-02-14 05:02:28

标签: c# serialization

让我们假设我必须在级别中序列化类Car的对象,例如内部和公共。公共级别中的某些属性不应序列化,因为它们是内部的。

此时我能想到的“最简单”的方法是使用继承:

class CarPublic {
  public int PropX {get;set}
}

class CarInternal: CarPublic {
  public string PropY {get;set}
}

然后我可以

object ToSerialize() {
 CarInternal car = GetCar();
 if( level == Level.Public ) { 
    return car as CarPublic;
 } else {
     return car;
 }
}

ToSerialize()的结果是由一个框架(我没有 控制)并序列化为JSON或XML。

为简单起见,我省略了XML序列化属性。

这感觉就像一个黑客,黑客只带你到目前为止。有没有更好的方法(方式?)来实现这个目标?

我认为现在很清楚,但我想避免为JSON和XML编写自己的序列化方法。

提前致谢 Tymek

== EDIT

为了澄清,我希望能够序列化多个级别:

class Car0 {
  public int PropA {get;set}
}

class Car1: Car0 {
  public string PropB {get;set}
}

class Car2: Car1 {
  public int PropC {get;set}
}

class Car3: Car2 {
  public string PropD {get;set}
}

object ToSerialize( Level level ) {
 Car3 car = GetCar();
 switch( level ) {
   case Level.Zero: return car as Car0;
   case Level.One: return car as Car1;
   case Level.Two: return car as Car3;
   case Level.Three: return car as Car4;
 }
 return null;
}

==选择方法

我将Marc Gravell的答案标记为答案,因为它提供了C#及其“标准”组件如何支持我所要求的一般信息。

但是我认为我的问题的最佳方法是使用如上所示的代理类 让这个类在这个多级模式中被序列化,方法如下所示。

public interface ICar {
    Car0 As0();
    Car1 As1();
    Car2 As2();
    Car3 As3();
 ...
 }

这样可以保持 Car0..3 类非常简单,只需要维护和理解属性。

2 个答案:

答案 0 :(得分:5)

这很大程度上取决于您使用的序列化框架。你提到xml和json - 首先要注意的是你可以装饰:

[XmlIgnore]
public int PropX {get;set;}

[ScriptIgnore]
public int PropX {get;set;}

XmlSerializerJavascriptSerializer会响应。如果您需要基于每个实例做出决策,则会有ShouldSerialize**Specified模式:

public bool ShouldSerializePropX() {
   // return true to serialize, false to omit
}

以上是基于名称的模式,由XmlSerializer和其他人使用;它有一个双胞胎:

[XmlIgnore, Browsable(false)]
public bool PropXSpecified {
    get { /* return true to serialize, false to omit */ }
    set { /* can just drop this value - don't need to assign */ }
}

你不需要做任何事情来连接它们 - 它们会自动工作。

不同的序列化程序允许不同的模式。

此外,有时您可以在运行时添加[XmlIgnore]之类的内容 - 例如通过XmlAttributeOverrides或任何给定序列化程序的等效项。

答案 1 :(得分:0)

您可以使用自定义属性修饰内部属性,指明应将其包含在内(或根据您的要求进行忽略),然后在ToSerialize中检查属性。

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class ShouldSerializeAttribute : Attribute { }

然后你得到的类定义如下:

class Car 
{
    [ShouldSerialize]
    public int PropX {get;set}

    // This property won't be serialized because it is internal
    public int PropY { get; set; }
}

ToSerialize看起来像是:

object ToSerialize() 
{
    Car car = GetCar();

    foreach(PropertyInfo propInfo in car.GetType().GetProperties())
    {
        if(ShouldSerialize(propInfo)) 
        { 
            return car;
        }
    }
}

ShouldSerialize的位置如下:

internal bool ShouldSerialize(PropertyInfo propInfo)
{
    return propInfo.GetCustomAttributes(typeof(ShouldSerializeAttribute), true).FirstOrDefault() != null;
}

<强>更新

基于@Bill对评论的见解。如果您希望仅在levelLevel.Public时序列化公共属性,则可以通过使用BindingFlags.DeclaredOnly标记反映类型的属性来实现此效果:

foreach(PropertyInfo propInfo in car.GetType().GetProperties(BindingFlags.DeclaredOnly))

这应返回仅由当前car实例声明的属性列表。