請正確實作 ISerializable
更新:2007 年 11 月
TypeName |
ImplementISerializableCorrectly |
CheckId |
CA2240 |
Category |
Microsoft.Usage |
Breaking Change |
Non Breaking |
原因
外部可見的型別可指派給 System.Runtime.Serialization.ISerializable 介面,而且會符合下列其中一個條件:
型別繼承而不是覆寫 ISerializable.GetObjectData 方法,而且型別所宣告的執行個體 (Instance) 欄位未標記 System.NonSerializedAttribute 屬性 (Attribute)。
型別並未密封,而且型別所實作的 GetObjectData 方法並非外部可見的或可覆寫的。
規則描述
繼承 System.Runtime.Serialization.ISerializable 介面的型別中,宣告的執行個體欄位不會自動加入序列化 (Serialization) 處理序 (Process) 中。若要加入欄位,型別必須實作 GetObjectData 方法和序列化建構函式。如果不應該將欄位序列化,請將 NonSerializedAttribute 屬性套用至欄位,明確指出這項決策。
在未密封的型別中,GetObjectData 方法的實作應該是外部可見的。因此,方法可以由衍生型別呼叫,並且可覆寫。
如何修正違規
若要修正此規則的違規情形,請將 GetObjectData 方法設為可見和可覆寫的,並確定所有執行個體欄位都加入序列化處理序中,或已明確標記 NonSerializedAttribute 屬性。
隱藏警告的時機
請勿隱藏此規則的警告。
範例
下列範例會顯示兩個違反規則的可序列化型別。
Imports System
Imports System.Security.Permissions
Imports System.Runtime.Serialization
Namespace Samples1
' Violates this rule
<Serializable()> _
Public Class Book
Implements ISerializable
Private ReadOnly _Title As String
Public Sub New(ByVal title As String)
If (title Is Nothing) Then Throw New ArgumentNullException("title")
_Title = title
End Sub
Protected Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext)
If (info Is Nothing) Then Throw New ArgumentNullException("info")
_Title = info.GetString("Title")
End Sub
Public ReadOnly Property Title() As String
Get
Return _Title
End Get
End Property
<SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags:=SecurityPermissionFlag.SerializationFormatter)> _
Public Sub GetObjectData(ByVal info As SerializationInfo, ByVal context As StreamingContext) _
Implements ISerializable.GetObjectData
If (info Is Nothing) Then Throw New ArgumentNullException("info")
info.AddValue("Title", _Title)
End Sub
End Class
' Violates this rule
<Serializable()> _
Public Class LibraryBook
Inherits Book
Private ReadOnly _CheckedOut As Date
Public Sub New(ByVal text As String, ByVal checkedOut As Date)
MyBase.New(text)
_CheckedOut = checkedOut
End Sub
Public ReadOnly Property CheckedOut() As Date
Get
Return _CheckedOut
End Get
End Property
End Class
End Namespace
using System;
using System.Security.Permissions;
using System.Runtime.Serialization;
namespace Samples1
{
// Violates this rule
[Serializable]
public class Book : ISerializable
{
private readonly string _Text;
public Book(string text)
{
if (text == null)
throw new ArgumentNullException("text");
_Text = text;
}
protected Book(SerializationInfo info, StreamingContext context)
{
if (info == null)
throw new ArgumentNullException("info");
_Text = info.GetString("Text");
}
public string Text
{
get { return _Text; }
}
[SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
if (info == null)
throw new ArgumentNullException("info");
info.AddValue("Text", _Text);
}
}
// Violates this rule
[Serializable]
public class LibraryBook : Book
{
private readonly DateTime _CheckedOut;
public LibraryBook(string text, DateTime checkedOut)
: base(text)
{
_CheckedOut = checkedOut;
}
public DateTime CheckedOut
{
get { return _CheckedOut; }
}
}
}
using namespace System;
using namespace System::Security::Permissions;
using namespace System::Runtime::Serialization;
namespace Samples1
{
// Violates this rule
[Serializable]
public ref class Book : ISerializable
{
private:
initonly String^ _Title;
public:
Book(String^ title)
{
if (title == nullptr)
throw gcnew ArgumentNullException("title");
_Title = title;
}
property String^ Title
{
String^ get()
{
return _Title;
}
}
protected:
Book(SerializationInfo^ info, StreamingContext context)
{
if (info == nullptr)
throw gcnew ArgumentNullException("info");
_Title = info->GetString("Title");
}
private:
[SecurityPermission(SecurityAction::LinkDemand, Flags = SecurityPermissionFlag::SerializationFormatter)]
void virtual GetObjectData(SerializationInfo^ info, StreamingContext context) sealed = ISerializable::GetObjectData
{
if (info == nullptr)
throw gcnew ArgumentNullException("info");
info->AddValue("Title", _Title);
}
};
// Violates this rule
[Serializable]
public ref class LibraryBook : Book
{
initonly DateTime _CheckedOut;
public:
LibraryBook(String^ title, DateTime checkedOut) : Book(title)
{
_CheckedOut = checkedOut;
}
property DateTime CheckedOut
{
DateTime get()
{
return _CheckedOut;
}
}
};
}
下列範例會藉由在 Book 類別提供可覆寫的 ISerializable.GetObjectData 實作,以及在 LibraryBook 類別提供 ISerializable.GetObjectData 的實作,以修正之前的兩個違規。
Imports System
Imports System.Security.Permissions
Imports System.Runtime.Serialization
Namespace Samples2
<Serializable()> _
Public Class Book
Implements ISerializable
Private ReadOnly _Title As String
Public Sub New(ByVal title As String)
If (title Is Nothing) Then Throw New ArgumentNullException("title")
_Title = title
End Sub
Protected Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext)
If (info Is Nothing) Then Throw New ArgumentNullException("info")
_Title = info.GetString("Title")
End Sub
Public ReadOnly Property Title() As String
Get
Return _Title
End Get
End Property
<SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags:=SecurityPermissionFlag.SerializationFormatter)> _
Protected Overridable Sub GetObjectData(ByVal info As SerializationInfo, ByVal context As StreamingContext) _
Implements ISerializable.GetObjectData
If (info Is Nothing) Then Throw New ArgumentNullException("info")
info.AddValue("Title", _Title)
End Sub
End Class
<Serializable()> _
Public Class LibraryBook
Inherits Book
Private ReadOnly _CheckedOut As Date
Public Sub New(ByVal text As String, ByVal checkedOut As Date)
MyBase.New(text)
_CheckedOut = checkedOut
End Sub
Protected Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext)
MyBase.New(info, context)
_CheckedOut = info.GetDateTime("CheckedOut")
End Sub
Public ReadOnly Property CheckedOut() As Date
Get
Return _CheckedOut
End Get
End Property
<SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags:=SecurityPermissionFlag.SerializationFormatter)> _
Protected Overrides Sub GetObjectData(ByVal info As System.Runtime.Serialization.SerializationInfo, _
ByVal context As System.Runtime.Serialization.StreamingContext)
MyBase.GetObjectData(info, context)
info.AddValue("CheckedOut", _CheckedOut)
End Sub
End Class
End Namespace
using System;
using System.Security.Permissions;
using System.Runtime.Serialization;
namespace Samples2
{
[Serializable]
public class Book : ISerializable
{
private readonly string _Title;
public Book(string title)
{
if (title == null)
throw new ArgumentNullException("title");
_Title = title;
}
protected Book(SerializationInfo info, StreamingContext context)
{
if (info == null)
throw new ArgumentNullException("info");
_Title = info.GetString("Title");
}
public string Title
{
get { return _Title; }
}
[SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
protected virtual void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("Title", _Title);
}
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
if (info == null)
throw new ArgumentNullException("info");
GetObjectData(info, context);
}
}
[Serializable]
public class LibraryBook : Book
{
private readonly DateTime _CheckedOut;
public LibraryBook(string title, DateTime checkedOut)
: base(title)
{
_CheckedOut = checkedOut;
}
protected LibraryBook(SerializationInfo info, StreamingContext context)
: base(info, context)
{
_CheckedOut = info.GetDateTime("CheckedOut");
}
public DateTime CheckedOut
{
get { return _CheckedOut; }
}
[SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
protected override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
info.AddValue("CheckedOut", _CheckedOut);
}
}
}
using namespace System;
using namespace System::Security::Permissions;
using namespace System::Runtime::Serialization;
namespace Samples2
{
[Serializable]
public ref class Book : ISerializable
{
private:
initonly String^ _Title;
public:
Book(String^ title)
{
if (title == nullptr)
throw gcnew ArgumentNullException("title");
_Title = title;
}
property String^ Title
{
String^ get()
{
return _Title;
}
}
protected:
Book(SerializationInfo^ info, StreamingContext context)
{
if (info == nullptr)
throw gcnew ArgumentNullException("info");
_Title = info->GetString("Title");
}
[SecurityPermission(SecurityAction::LinkDemand, Flags = SecurityPermissionFlag::SerializationFormatter)]
void virtual GetObjectData(SerializationInfo^ info, StreamingContext context) = ISerializable::GetObjectData
{
if (info == nullptr)
throw gcnew ArgumentNullException("info");
info->AddValue("Title", _Title);
}
};
[Serializable]
public ref class LibraryBook : Book
{
initonly DateTime _CheckedOut;
public:
LibraryBook(String^ title, DateTime checkedOut)
: Book(title)
{
_CheckedOut = checkedOut;
}
property DateTime CheckedOut
{
DateTime get()
{
return _CheckedOut;
}
}
protected:
LibraryBook(SerializationInfo^ info, StreamingContext context) : Book(info, context)
{
_CheckedOut = info->GetDateTime("CheckedOut");
}
[SecurityPermission(SecurityAction::LinkDemand, Flags = SecurityPermissionFlag::SerializationFormatter)]
void virtual GetObjectData(SerializationInfo^ info, StreamingContext context) override
{
Book::GetObjectData(info, context);
info->AddValue("CheckedOut", _CheckedOut);
}
};
}