CA2240: ISerializable을 올바르게 구현하십시오.
TypeName |
ImplementISerializableCorrectly |
CheckId |
CA2240 |
범주 |
Microsoft.Usage |
변경 수준 |
주요 변경 아님 |
원인
외부에서 볼 수 있는 형식을 System.Runtime.Serialization.ISerializable 인터페이스에 할당할 수 있고 다음 조건 중 하나가 참입니다.
형식이 ISerializable.GetObjectData 메서드를 상속하지만 재정의하지 않고 형식이 System.NonSerializedAttribute 특성으로 표시되지 않은 인스턴스 필드를 선언합니다.
형식이 sealed가 아니고 형식이 외부에서 볼 수 없고 재정의할 수 없는 GetObjectData 메서드를 구현합니다.
규칙 설명
System.Runtime.Serialization.ISerializable 인터페이스를 상속하는 형식에 선언된 인스턴스 필드는 serialization 프로세스에 자동으로 포함되지 않습니다. 필드를 포함하려면 형식은 GetObjectData 메서드 및 serialization 생성자를 구현해야 합니다. 필드를 serialize하지 않아야 할 경우에는 필드에 NonSerializedAttribute 특성을 적용하여 이러한 결정 내용을 명시적으로 나타냅니다.
sealed가 아닌 형식의 경우 외부에서 GetObjectData 메서드의 구현을 볼 수 있어야 합니다. 따라서 해당 메서드는 파생 형식에서 호출할 수 있으며 재정의 가능합니다.
위반 문제를 해결하는 방법
이 규칙 위반 문제를 해결하려면 GetObjectData 메서드를 노출하고 재정의 가능하도록 만든 다음 모든 인스턴스 필드가 serialization 프로세스에 포함되었는지 또는 NonSerializedAttribute 특성이 명시적으로 표시되었는지 확인합니다.
경고를 표시하지 않는 경우
이 규칙에서는 경고를 표시해야 합니다.
예제
다음 예제에서는 이 규칙을 위반하는 serialize 가능한 두 형식을 보여 줍니다.
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]의 재정의 가능한 구현을 제공하고 Library 클래스에 [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);
}
};
}
관련 규칙
CA2236: ISerializable 형식에서 기본 클래스 메서드를 호출하십시오.
CA2229: serialization 생성자를 구현하십시오.
CA2238: serialization 메서드를 올바르게 구현하십시오.
CA2235: 모두 serialize할 수 없는 필드로 표시하십시오.
CA2237: ISerializable 형식을 SerializableAttribute로 표시하십시오.