为什么C#SerializedAttribute是密封的?

时间:2012-11-09 22:21:05

标签: c#

我试图创建一个隐含[Serializable]的属性,但我注意到这个SerializableAttribute类是密封的。

在Java中,可以创建一个继承自MyInterface接口的接口(例如,Serializable),因此MyInterface的所有子类也可以序列化,甚至是子类-sub类就是这样。

假设我正在创建一个ORM,我希望客户将他们的实体类注释为[DatabaseEntity]但是为了确保实体是可序列化的,我还需要让他们用额外的{{{{{{{{ 1}}看起来不那么紧凑和整洁。

我想知道为什么[Serializable] SerializableAttribute 以及为什么 sealed 这意味着可序列化类的子类不会除非明确说明,否则可序列化。这些设计选择背后的动机是什么?

4 个答案:

答案 0 :(得分:4)

SerializableAttribute仅由BinaryFormatter使用。如果您正在编写自己的序列化器,那么请不要担心。

sealed关键字应用于属性,而不是与属性关联的类。它说SerializableAttribute不能被子类化。

BinaryFormatter使用了选择加入模式。任何类(或子类)都必须指定它是可序列化的。这就是使用Inherited=false的原因。

答案 1 :(得分:1)

建议最佳做法是所有 .Net属性应密封,according to Microsoft

  

.NET Framework类库提供了检索自定义属性的方法。默认情况下,这些方法搜索属性继承层次结构;例如System.Attribute.GetCustomAttribute搜索指定的属性类型,或任何扩展指定属性类型的属性类型。 关闭属性会消除通过继承层次结构的搜索,可以提高性能。 [我的重点]

所以[Serializable]是密封的,因为.Net反射检查属性的速度更快。成本是您无法继承和扩展SerializableAttribute

如果需要,您可以创建自己的未密封属性(但是您会收到代码分析警告)。

对于它们所适用的类的继承中如何使用属性,这有点令人困惑。最好使用一个例子:

[Serializable]
public class A
{
    public int SimpleSerialisableProperty { get; set;}
}

public class B : A
{
    public C ComplexReferenceProperty { get; set; }
}

[Serializable]
public class D : A
{
    public bool AnotherSerialisableProperty { get; set;}
}

你问为什么SerializableAttribute.Inherited = false这就是原因:

  • 班级A被标记为[Serializable],而且是B

  • 但是,类A继承B并使用不可序列化的属性扩展它。如果.Net尝试序列化Inherited = false,则会遇到错误。

  • A告诉.Net,因为[Serializable]已被标记为D并非每个继承它的类都可以序列化。

  • 现在,类A继承了[Serializable]并且是可序列化的,因此它获得了自己的abstract属性。

最后,在设计属性方面,扩展行为的好方法(属性网格中的优秀UI编辑器等)。然而,他们在强制执行时非常糟糕。如果您需要客户以特定方式实现其实体类,那么interface基类或[Serializable]是一种更好的方法。如果你把它作为一个属性,那么你基本上让他们知道{{1}}是一个你可以处理的选项。

答案 2 :(得分:0)

序列化不是一件神奇的事情,您不需要任何属性来序列化对象。这是将类的属性和字段写入流的过程(属性只是序列化程序有关在输出对象时如何表现的指令)。

请参阅此过度简化的序列化程序代码,该代码完全忽略所有属性,包括NonSerializable

object obj = yourObject;

var props = obj.GetType()
               .GetProperties()
               .ToDictionary(p => p.Name, p => p.GetValue(obj, null));

string serializedText = String.Join("\n",
              props.Select(kv => kv.Key + "=" + kv.Value ?? kv.Value.ToString()));

例如,上面的代码将给出

IsEmpty=False
X=3
Y=5

代表object obj = new Point(3,5);

反序列化过程将是读取这些值并相应地设置属性。

答案 3 :(得分:-2)

将[Serializable]属性放在要序列化的类的顶部。序列化是选择加入过程。您必须为要序列化的每个类手动执行此操作。还有许多其他关键字。