簡體   English   中英

為什么C#SerializedAttribute是密封的?

[英]Why is the C# SerializedAttribute is sealed?

我試圖創建一個暗示[Serializable]的屬性,但我注意到這個SerializableAttribute類是密封的。

在Java中,可以創建一個繼承自Serializable接口的接口(例如, MyInterface ),因此MyInterface所有子類也可以序列化,甚至它的子子類也是如此。

假設我正在創建一個ORM,我希望客戶將他們的實體類注釋為[DatabaseEntity]但是為了確保實體是可序列化的,我還需要讓他們用額外的[Serializable]來定義他們的類,這看起來並不像非常緊湊和整潔。

我想知道為什么SerializableAttribute類被sealed ,為什么有Inherited=false這意味着可序列化類的子類不可序列化,除非明確說明。 這些設計選擇背后的動機是什么?

SerializableAttribute僅由BinaryFormatter使用。 如果您正在編寫自己的序列化程序,請不要擔心。

sealed關鍵字應用於屬性,而不是與屬性關聯的類。 它說SerializableAttribute不能被子類化。

BinaryFormatter使用選擇加入模型。 任何類(或子類)都必須指定它是可序列化的。 這就是使用Inherited=false原因。

根據微軟的說法,建議最佳做法是密封所有 .Net屬性:

.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並使用不可序列化的屬性擴展它。 如果.Net嘗試序列化B ,則會遇到錯誤。

  • 那個Inherited = false告訴.Net,因為A被標記為[Serializable]並不是每個繼承它的類都是可序列化的。

  • 現在D類繼承A並且是可序列化的,因此它獲得了自己的[Serializable]屬性。

最后,在設計屬性方面是擴展行為的好方法(屬性網格中的優秀UI編輯器等)。 然而,他們在執行它時非常糟糕。 如果您需要客戶以特定方式實現其實體類,那么abstract基類或interface是一種更好的方法。 如果你把它作為一個屬性,那么你基本上讓他們知道[Serializable]是一個你可以處理的選項。

序列化不是一件神奇的事情,您不需要任何屬性來序列化對象。 這是將類的屬性和字段寫入流的過程(屬性只是序列化程序有關在輸出對象時如何表現的指令)。

請參閱此過度簡化的序列化程序代碼,該代碼完全忽略包括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

for object obj = new Point(3,5);

反序列化過程將是讀取這些值並相應地設置屬性。

將[Serializable]屬性放在要序列化的類的頂部。 序列化是選擇加入過程。 您必須為要序列化的每個類手動執行此操作。 還有很多其他關鍵字。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM