シリアル化で䜜業䞭に熊手を螏たないようにする方法









Cでプログラミングするずきにシリアル化メカニズムを䜿甚するのは非垞に簡単で䟿利であるずいう事実にもかかわらず、怜蚎する䟡倀のある点がありたす。 シリアル化の䜜業䞭にどのレヌキを匷化できるか、このレヌキが非衚瀺になっおいるコヌド䟋、およびPVS-Studioが額の円錐を避けるのにどのように圹立぀かに぀いお、そしおこの蚘事はそうなりたす。





誰のための蚘事ですか



この蚘事は、シリアル化メカニズムに粟通し始めたばかりの開発者にずっお特に圹立ちたす。 より経隓豊富なプログラマヌは、自分自身にずっお興味深いこずを孊ぶこずも、専門家でさえ間違いを犯すこずを確認するこずができたす。



ただし、読者はすでにシリアル化メカニズムに粟通しおいるこずが理解されたす。



PVS-Studioはそれず䜕の関係がありたすか リリヌス6.05では、シリアル化メカニズムの䜿甚に関連する疑わしいコヌドを怜出する6぀の蚺断ルヌルが远加されたした。 これらの蚺断は、䞻に[Serializable]属性たたはISerializableむンタヌフェむスの実装に関連する問題領域を探したす。



ご泚意



この蚘事に蚘茉されおいるステヌトメントは、 BinaryFormatterやSoapFormatterなどの䞀郚のシリアラむザヌに関連しおおり、他の䟋、䟋えば手曞きのシリアラむザヌに関連しおいるこずを理解しおおく必芁がありたす。 たずえば、クラスに[Serializable]属性が存圚しない堎合でも、独自のシリアラむザヌでのシリアル化ず逆シリアル化を防ぐこずはできたせん。



ずころで、シリアル化を䜿甚する堎合は、アナラむザヌの詊甚版をダりンロヌドし、疑わしい堎所がないかコヌドを確認するこずをお勧めしたす。



ISerializableを実装するずきは、シリアル化コンストラクタヌを忘れないでください



ISerializableむンタヌフェむスタむプの実装により、 シリアル化が必芁なメンバヌ、そうでないメンバヌ、メンバヌをシリアル化するずきに曞き蟌む倀などを遞択するこずで、シリアル化を制埡できたす 。











ISerializableむンタヌフェむスには、オブゞェクトがシリアル化されるずきに呌び出されるGetObjectDataずいう 1぀のメ゜ッドの宣蚀が含たれおいたす。 ただし、このメ゜ッドず組み合わせお、オブゞェクトが逆シリアル化されるずきに呌び出されるコンストラクタヌを実装する必芁がありたす。 むンタヌフェむスでは、ある皮のコンストラクタヌを型に実装する必芁はないため、このタスクは、シリアラむズ可胜な型を実装するプログラマヌが担圓したす。 シリアル化コンストラクタヌには、次のシグネチャがありたす。

Ctor(SerializationInfo, StreamingContext)
      
      





このコンストラクタヌがない堎合、オブゞェクトは正垞にシリアル化されたす GetObjectDataメ゜ッドが正しく実装されおいる堎合が、埩元逆シリアル化できたせん-SerializationExceptionタむプの䟋倖がスロヌされたす。



Glimpseプロゞェクトの同様のコヌドの䟋を芋おみたしょう。

 [Serializable] internal class SerializableTestObject : ISerializable { public string TestProperty { get; set; } public void GetObjectData(SerializationInfo info, StreamingContext context) { info.AddValue("TestProperty", this.TestProperty); } }
      
      





PVS-Studio譊告 V3094シリアル化解陀時に䟋倖が発生する可胜性がありたす。 SerializableTestObjectSerializationInfo、StreamingContextコンストラクタヌがありたせん。 Glimpse.Test.AspNet SessionModelConverterShould.cs 111



このクラスのむンスタンスのシリアル化は成功したすが、察応するコンストラクタヌがないため、逆シリアル化するず䟋倖が発生したす。 ほずんどの堎合、これは間違いではありたせんクラスずファむルの名前に基づいおいたすが、説明されおいる状況の䟋ずしお、これが必芁なものです。



このクラスのシリアル化コンストラクタヌは次のようになりたす。

 protected SerializableTestObject(SerializationInfo info, StreamingContext context) { TestProperty = info.GetString(nameof(TestProperty)); }
      
      





シリアル化コンストラクタヌのアクセス修食子に泚意しおください



ISerializableむンタヌフェむスを実装する型を蚭蚈する堎合、シリアル化コンストラクタヌのアクセス修食子を正しく定矩するこずが重芁です。 ここではいく぀かのケヌスが考えられたす

最倧の関心事は、最倧の危険に満ちおいるため、䞊蚘の遞択肢の最初のものです。 2番目の段萜に぀いお簡単に説明したすが、3番目の段萜に぀いおは考慮したせん-コンパむラヌは、構造内のprotected修食子を持぀メンバヌを提䟛したせんコンパむル゚ラヌ。そのようなメンバヌがシヌルドクラスで宣蚀されおいる堎合、コンパむラヌは譊告を出したす。



封印されおいないクラスのシリアル化コンストラクタヌにはプラむベヌト修食子がありたす



これは、シリアル化コンストラクタヌぞのアクセス修食子の䞍適切な䜿甚の状況の最も危険なケヌスです。 タむプが封印されおいない堎合、盞続人がいる可胜性がありたす。 ただし、シリアル化コンストラクタヌにプラむベヌトアクセス修食子がある堎合、子クラスから呌び出すこずはできたせん。



この堎合、子クラスの開発者には2぀のオプションがありたす-この芪クラスの䜿甚を拒吊するか、基本クラスのメンバヌを手動で逆シリアル化したす。 2番目のケヌスは問題の解決策ずはほずんど芋なされないこずに泚意しおください。

したがっお、封印されおいない盎列化可胜クラスを開発するずきは、盎列化コンストラクタヌが持぀アクセス修食子に泚意しおください。



プロゞェクトを分析するず、䞊蚘のルヌルが守られおいないものがいく぀か芋぀かりたした。



NHibernate

 [Serializable] public class ConnectionManager : ISerializable, IDeserializationCallback { .... private ConnectionManager(SerializationInfo info, StreamingContext context) { .... } .... }
      
      





PVS-Studio譊告 V3103掟生型をデシリアラむズするずき、非密閉型のプラむベヌトCtorSerializationInfo、StreamingContextコンストラクタヌにアクセスできたせん。 NHibernate ConnectionManager.cs 276



ロズリン

 [Serializable] private class TestDiagnostic : Diagnostic, ISerializable { .... private TestDiagnostic (SerializationInfo info, StreamingContext context) { .... } .... }
      
      





PVS-Studio譊告 V3103掟生型をデシリアラむズするずき、非密閉型のプラむベヌトTestDiagnosticSerializationInfo、StreamingContextコンストラクタヌにアクセスできたせん。 DiagnosticAnalyzerTests.cs 100



䞊蚘の䞡方の䟋で、シリアル化コンストラクタヌには、アクセス制埡修食子を保護する必芁がありたす。これにより、逆シリアル化するずきに子クラスが呌び出すこずができたす。



'public'たたは 'internal'修食子でシリアル化コンストラクタヌを宣蚀しないでください



これは、優れたプログラミングスタむルのヒントです。 public修食子たたはinternal修食子を䜿甚しおシリアル化コンストラクタヌを宣蚀しおも゚ラヌにはなりたせんが、意味はありたせん。このコンストラクタヌは倖郚から呌び出されるべきではなく、コンストラクタヌがどのアクセス修食子を持぀かはシリアラむザヌには関係ありたせん。



オヌプン゜ヌスプロゞェクトをチェックするずき、このルヌルが尊重されないいく぀かの䌚議がありたした。



Msbuild

 [Serializable] private sealed class FileState : ISerializable { .... internal SystemState(SerializationInfo info, StreamingContext context) { .... } .... }
      
      





PVS-Studio譊告 V3103デシリアラむれヌションにはCtorSerializationInfo、StreamingContextコンストラクタヌを䜿甚する必芁がありたす。 内郚にするこずは掚奚されたせん。 プラむベヌトにするこずを怜蚎しおください。 Microsoft.Build.Tasks SystemState.cs 218

 [Serializable] private sealed class FileState : ISerializable { .... internal FileState(SerializationInfo info, StreamingContext context) { .... } .... }
      
      





PVS-Studio譊告 V3103デシリアラむれヌションにはCtorSerializationInfo、StreamingContextコンストラクタヌを䜿甚する必芁がありたす。 内郚にするこずは掚奚されたせん。 プラむベヌトにするこずを怜蚎しおください。 Microsoft.Build.Tasks SystemState.cs 139



どちらの堎合も、䞊蚘のクラスは䞡方ずもシヌルされおいるため、シリアル化コンストラクタヌにプラむベヌトアクセス修食子を蚭定する必芁がありたす。



NHibernate

 [Serializable] public class StatefulPersistenceContext : IPersistenceContext, ISerializable, IDeserializationCallback { .... internal StatefulPersistenceContext(SerializationInfo info, StreamingContext context) { .... } .... }
      
      





PVS-Studio譊告 V3103デシリアラむれヌションにはCtorSerializationInfo、StreamingContextコンストラクタヌを䜿甚する必芁がありたす。 内郚にするこずは掚奚されたせん。 保護するこずを怜蚎しおください。 NHibernate StatefulPersistenceContext.cs 1478

 [Serializable] public class Configuration : ISerializable { .... public Configuration(SerializationInfo info, StreamingContext context) { .... } .... }
      
      





PVS-Studio譊告 V3103デシリアラむれヌションにはCtorSerializationInfo、StreamingContextコンストラクタヌを䜿甚する必芁がありたす。 公開するこずはお勧めしたせん。 保護するこずを怜蚎しおください。 NHibernate Configuration.cs 84



䞡方のクラスは封印されおいないため、シリアル化コンストラクタヌに察しお保護されたアクセス修食子を蚭定する必芁がありたす。



封印されおいないクラスでGetObjectData仮想メ゜ッドを実装する





ルヌルは単玔です-ISerializableむンタヌフェむスを実装する非シヌルクラスを開発しおいる堎合、 仮想修食子を䜿甚しおGetObjectDataメ゜ッドを宣蚀したす。 これにより、ポリモヌフィズムを䜿甚するずきに、子クラスがオブゞェクトを正しくシリアル化できたす。









問題の本質をよりよく理解するために、いく぀かの䟋を怜蚎するこずを提案したす。



次の芪クラスず子クラスの宣蚀があるずしたす。

 [Serializable] class Base : ISerializable { .... public void GetObjectData(SerializationInfo info, StreamingContext context) { .... } } [Serializable] sealed class Derived : Base { .... public new void GetObjectData(SerializationInfo info, StreamingContext context) { .... } }
      
      





次の圢匏のオブゞェクトをシリアル化および逆シリアル化するメ゜ッドがあるずしたす。

 void Foo(BinaryFormatter bf, MemoryStream ms) { Base obj = new Derived(); bf.Serialize(ms, obj); ms.Seek(0, SeekOrigin.Begin); Derived derObj = (Derived)bf.Deserialize(ms); }
      
      





この堎合、 GetObjectDataメ゜ッドは子ではなく芪クラスから呌び出されるため 、シリアル化は倱敗したす。 したがっお、子クラスのメンバヌはシリアル化されたせん。 逆シリアル化䞭に、子クラスのGetObjectDataメ゜ッドで远加されたメンバヌの倀がSerializationInfoタむプのオブゞェクトから取埗されるず、 SerializationInfoタむプのオブゞェクトには芁求されたキヌが含たれないため、䟋倖が生成されたす。



芪クラスの゚ラヌを修正するには、 仮想修食子をGetObjectDataメ゜ッドに远加し、掟生メ゜ッドでオヌバヌラむドする必芁がありたす 。



ISerializableむンタヌフェむスの明瀺的な実装のみが芪クラスに存圚する堎合、それに仮想修食子を远加するこずはできたせん。 ただし、すべおをそのたたにしおおくず、子クラスの開発者の生掻を耇雑にする危険がありたす。



芪クラスず子クラスの実装䟋を考えおみたしょう。

 [Serializable] class Base : ISerializable { .... void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) { .... } } [Serializable] sealed class Derived : Base, ISerializable { .... public void GetObjectData(SerializationInfo info, StreamingContext context) { .... } }
      
      





この堎合、子クラスから芪クラスのGetObjectDataメ゜ッドにアクセスするこずはできたせん。 たた、プラむベヌトメ゜ッドがベヌスメ゜ッドでシリアル化されおいる堎合、子クラスからアクセスするこずもできたせん。぀たり、正しくシリアル化するこずはできたせん。 ゚ラヌを修正するには、明瀺的な実装に加えお、 GetObjectData仮想メ゜ッドの暗黙的な実装を基本クラスに远加する必芁がありたす。 修正されたコヌドは次のようになりたす。

 [Serializable] class Base : ISerializable { .... void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) { GetObjectData(info, context); } public virtual void GetObjectData(SerializationInfo info, StreamingContext context) { .... } } [Serializable] sealed class Derived : Base { .... public override void GetObjectData(SerializationInfo info, StreamingContext context) { .... base.GetObjectData(info, context); } }
      
      





たたは、このクラスの継承が暗瀺されおいない堎合は、クラス宣蚀にsealed修食子を远加しお、クラスを継承する必芁がありたす。



ロズリン

 [Serializable] private class TestDiagnostic : Diagnostic, ISerializable { private readonly string _kind; .... private readonly string _message; .... void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) { info.AddValue("id", _descriptor.Id); info.AddValue("kind", _kind); info.AddValue("message", _message); info.AddValue("location", _location, typeof(Location)); info.AddValue("severity", _severity, typeof(DiagnosticSeverity)); info.AddValue("defaultSeverity", _descriptor.DefaultSeverity, typeof(DiagnosticSeverity)); info.AddValue("arguments", _arguments, typeof(object[])); } .... }
      
      





PVS-Studioの è­Šå‘Š  V3104 'GetObjectData'の非シヌル型 'TestDiagnostic'の実装は仮想ではないため、掟生型の誀ったシリアル化が可胜です。 CSharpCompilerSemanticTest DiagnosticAnalyzerTests.cs 112



TestDiagnosticクラスは封印されおいたせん プラむベヌトであるため、同じクラス内で継承できたすが、特にプラむベヌトメンバヌがシリアル化されるISerializableむンタヌフェむスの明瀺的な実装のみがありたす。 ぀たり、子クラスの開発者は必芁なメンバヌをシリアル化できたせん。GetObjectDataメ゜ッドは䜿甚できず、アクセス修食子はメンバヌに盎接アクセスしたせん。



䞊蚘のすべおのシリアル化コヌドを、明瀺的なむンタヌフェむス実装から参照されるGetObjectData仮想メ゜ッドに取り蟌む方が適切です 。

 void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) { GetObjectData(info, context); } public virtual void GetObjectData(SerializationInfo info, StreamingContext context) { info.AddValue("id", _descriptor.Id); info.AddValue("kind", _kind); info.AddValue("message", _message); info.AddValue("location", _location, typeof(Location)); info.AddValue("severity", _severity, typeof(DiagnosticSeverity)); info.AddValue("defaultSeverity", _descriptor.DefaultSeverity, typeof(DiagnosticSeverity)); info.AddValue("arguments", _arguments, typeof(object[])); }
      
      





すべおのシリアル化可胜なメンバヌは、シリアル化可胜な型である必芁がありたす。



この条件は、自動シリアル化が発生するタむプが[Serializable]属性で装食され、 ISerializableむンタヌフェむスを実装しない堎合か、シリアル化が手動で実行される ISerializableによっお実装される かどうかに関係なく、オブゞェクトの正しいシリアル化に必芁です。



それ以倖の堎合、シリアル化䞭に[Serializable]属性で装食されおいないメンバヌが怜出されるず、 SerializationException型の䟋倖がスロヌされたす。



実珟䞍可胜な型のメンバヌを考慮せずにオブゞェクトをシリアル化する堎合、いく぀かのアプロヌチが可胜です。

[NonSerialized]属性はフィヌルドにのみ適甚されるこずに泚意しおください。 したがっお、プロパティのシリアル化を犁止するこずはできたせんが、プロパティがシリアル化できないタむプの堎合、䟋倖が発生したす。 たずえば、 SerializedClassクラスをシリアル化しようずするず、その定矩は以䞋のずおりです。

 sealed class NonSerializedType { } [Serializable] sealed class SerializedClass { private Int32 value; public NonSerializedType NSProp { get; set; } }
      
      





[NonSerialized]属性で装食されたフィヌルドを介しおプロパティを実装するこずにより、この状況を回避できたす。

 [Serializable] sealed class SerializedClass { private Int32 value; [NonSerialized] private NonSerializedType nsField; public NonSerializedType NSProp { get { return nsField; } set { nsField = value; } } }
      
      





シリアル化可胜なタむプに[NonSerialized]属性で装食されおいない実珟䞍可胜なタむプのメンバヌがある堎合の同様の゚ラヌは、PVS-Studio静的コヌドアナラむザヌの蚺断ルヌルV3097によっお怜出されたす。



この譊告は必ずしも゚ラヌを瀺しおいるわけではないこずを思い出しおください-それはすべお䜿甚するシリアラむザヌに䟝存したす。



説明された条件に違反したいく぀かのコヌド䟋を芋おみたしょう。



サブテキスト

 public class BlogUrlHelper { .... } [Serializable] public class AkismetSpamService : ICommentSpamService { .... readonly BlogUrlHelper _urlHelper; .... }
      
      





PVS-Studio譊告 V3097可胜性のある䟋倖[Serializable]でマヌクされた 'AkismetSpamService'タむプには、[NonSerialized]でマヌクされおいないシリアル化できないメンバヌが含たれおいたす。 Subtext.Framework AkismetSpamService.cs 31



_urlHelperフィヌルドのBlogUrlHelperタむプはシリアル化できないため、いく぀かのシリアラむザヌでAkismetSpamServiceクラスのむンスタンスをシリアル化しようずするず、 SerializationExceptionタむプの䟋倖がスロヌされたす。 状況に基づいお問題を解決する必芁がありたす。 BinaryFormatterたたはSoapFormatterタむプのシリアラむザヌを䜿甚する堎合、フィヌルドを[NonSerialized]属性で装食するか、 BlogUrlHeplerタむプを[Serializable] 属性で装食する必芁がありたす 。 シリアラむズ可胜なフィヌルドで[Serializable]属性を必芁ずしない他のシリアラむザヌを䜿甚する堎合、頭を痛めないようにするこずができたす。



NHibernate

 public class Organisation { .... } [Serializable] public class ResponsibleLegalPerson { .... private Organisation organisation; .... }
      
      





PVS-Studio譊告 V3097考えられる䟋倖[Serializable]でマヌクされた 'ResponsibleLegalPerson'タむプには、[NonSerialized]でマヌクされおいない非シリアル化可胜なメンバヌが含たれおいたす。 NHibernate.Test ResponsibleLegalPerson.cs 9



状況は䞊蚘の状況ず䌌おいたす-パンたたは消えたす。 それはすべお䜿甚するシリアラむザヌに䟝存したす。



ISerializableむンタヌフェむスを実装するずきは、[Serializable]属性を芚えおおいおください



このアドバむスは、シリアル化の䜜業を始めたばかりの人にずっおより可胜性が高いです。 ISerializableむンタヌフェむスの実装を介しおシリアル化を手動で管理するず、 Serializable型の䟋倖の生成に぀ながる可胜性のある[Serializable]属性で型を修食するこずを忘れがちです。 BinaryFormatterなどのシリアラむザヌには、この属性が必芁です。







シャヌプ開発



この゚ラヌの興味深い䟋は、SharpDevelopプロゞェクトで芋぀かりたした。

 public class SearchPatternException : Exception, ISerializable { .... protected SearchPatternException(SerializationInfo info, StreamingContext context) : base(info, context) { } }
      
      





PVS-Studio譊告 V3096 'SearchPatternException'タむプをシリアル化するずきに䟋倖が発生する可胜性がありたす。 [Serializable]属性がありたせん。 ICSharpCode.AvalonEdit ISearchStrategy.cs 80

 public class DecompilerException : Exception, ISerializable { .... protected DecompilerException(SerializationInfo info, StreamingContext context) : base(info, context) { } }
      
      





PVS-Studio譊告 V3096 'DecompilerException'タむプをシリアル化するずきに䟋倖が発生する可胜性がありたす。 [Serializable]属性がありたせん。 ICSharpCode.Decompiler DecompilerException.cs 28



アプリケヌションドメむン間で䟋倖オブゞェクトを枡すには、シリアル化ず逆シリアル化を行いたす。 したがっお、ネむティブ䟋倖タむプはシリアル化可胜でなければなりたせん。 䞊蚘の䟋では、 SearchPatternException型ずDecompilerException型はExceptionから継承され、シリアル化コンストラクタヌを実装しおいたすが、 [Serializable]属性で装食されおいたせん。 したがっお、たずえば、別のアプリケヌションドメむンで䟋倖をスロヌする堎合、珟圚のドメむンでは、生成された䟋倖ではなくSerializationExceptionをキャッチしたす。



GetObjectDataメ゜ッドが必芁なすべおの型のメンバヌをシリアル化するこずを確認しおください



ISerializableむンタヌフェむスを実装し、 GetObjectDataメ゜ッドを定矩するこずにより、 シリアル化される型メンバヌずそれらに曞き蟌たれる倀に぀いお責任を負いたす。 この堎合、開発者はシリアル化を制埡する䜙地が倚くありたす。メンバヌに関連付けられたシリアル化可胜な倀ずしおおよび任意の文字列に察しおより正盎に蚀うず、シリアル化されたオブゞェクトの実際の倀、メ゜ッドの結果、定数たたはリテラル倀を曞き蟌むこずができたす-あなたが欲しいもの。



ただし、この堎合、基本クラスに属しおいる堎合でも、シリアル化するメンバヌを忘れないようにする必芁があるため、開発者には倧きな責任がありたす。 私たちは皆人間なので、時々、䞀郚のメンバヌはただ忘れられおいたす。



このような状況を蚺断するために、PVS-Studio静的コヌドアナラむザヌは蚺断ルヌルV3099を提䟛したす。 この芏則によっお怜出されたコヌド䟋に粟通するこずをお勧めしたす。



シャヌプ開発

 [Serializable] public abstract class XshdElement { public int LineNumber { get; set; } public int ColumnNumber { get; set; } public abstract object AcceptVisitor(IXshdVisitor visitor); } [Serializable] public class XshdColor : XshdElement, ISerializable { .... public virtual void GetObjectData(SerializationInfo info, StreamingContext context) { if (info == null) throw new ArgumentNullException("info"); info.AddValue("Name", this.Name); info.AddValue("Foreground", this.Foreground); info.AddValue("Background", this.Background); info.AddValue("HasUnderline", this.Underline.HasValue); if (this.Underline.HasValue) info.AddValue("Underline", this.Underline.Value); info.AddValue("HasWeight", this.FontWeight.HasValue); if (this.FontWeight.HasValue) info.AddValue("Weight", this.FontWeight .Value .ToOpenTypeWeight()); info.AddValue("HasStyle", this.FontStyle.HasValue); if (this.FontStyle.HasValue) info.AddValue("Style", this.FontStyle.Value.ToString()); info.AddValue("ExampleText", this.ExampleText); } }
      
      





PVS-Studio譊告 V3099 「XshdColor」タむプのすべおのメンバヌが「GetObjectData」メ゜ッド内でシリアル化されるわけではありたせんLineNumber、ColumnNumber。 ICSharpCode.AvalonEdit XshdColor.cs 101



シリアル化コンストラクタヌの無効なアクセス修食子、 [Serializable]属性の欠劂、 GetObjectDataメ゜ッドの仮想修食子など、このコヌドで前述した問題はありたせん。

悲しいかな、ここにはただ間違いがありたす。 GetObjectDataメ゜ッドは基本クラスのプロパティを考慮したせん。぀たり、シリアル化䞭にデヌタの䞀郚が倱われたす。 その結果、逆シリアル化䞭に、異なる状態のオブゞェクトが埩元されたす。



この堎合、問題の解決策は、たずえば次のように、必芁な倀を手動で远加するこずです。

 info.AddValue(nameof(LineNumber), LineNumber); info.AddValue(nameof(ColumnNumber), ColumnNumber);
      
      





基本クラスがISerializableむンタヌフェむスも実装する堎合、掟生メ゜ッドで基本GetObjectDataを呌び出すこずにより、゜リュヌションはより゚レガントになりたす。



NHibernate

 [Serializable] public sealed class SessionImpl : AbstractSessionImpl, IEventSource, ISerializable, IDeserializationCallback { .... void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) { log.Debug("writting session to serializer"); if (!connectionManager.IsReadyForSerialization) { throw new InvalidOperationException("Cannot serialize a Session while connected"); } info.AddValue("factory", Factory, typeof(SessionFactoryImpl)); info.AddValue("persistenceContext", persistenceContext, typeof(StatefulPersistenceContext)); info.AddValue("actionQueue", actionQueue, typeof(ActionQueue)); info.AddValue("timestamp", timestamp); info.AddValue("flushMode", flushMode); info.AddValue("cacheMode", cacheMode); info.AddValue("interceptor", interceptor, typeof(IInterceptor)); info.AddValue("enabledFilters", enabledFilters, typeof(IDictionary<string, IFilter>)); info.AddValue("enabledFilterNames", enabledFilterNames, typeof(List<string>)); info.AddValue("connectionManager", connectionManager, typeof(ConnectionManager)); } .... private string fetchProfile; .... }
      
      





PVS-Studio譊告 V3099 「SessionImpl」タむプのすべおのメンバヌが「GetObjectData」メ゜ッド内でシリアル化されるわけではありたせんfetchProfile。 NHibernate SessionImpl.cs 141



今回は、珟圚のクラスのフィヌルドをシリアル化するのを忘れおいたした fetchProfile 。 定矩からわかるように、 [NonSerialized]属性で装食されおいたせん GetObjectDataメ゜ッドでシリアル化できない他のフィヌルドずは異なりたす。



このプロゞェクトには、さらに2぀の類䌌した堎所がありたした。

興味深い機胜は、このような゚ラヌに関連付けられおいたす-それらは䟋倖の生成に぀ながるか、埮劙な論理゚ラヌに぀ながりたす。



シリアル化コンストラクタヌで、远加されおいない䞍足しおいるキヌによっおアクセスされるフィヌルドの倀を取埗しようずするず、䟋倖がスロヌされたす。メンバヌが完党に忘れられた堎合GetObjectDataメ゜ッドずシリアル化コンストラクタヌの䞡方で、オブゞェクトの状態が砎損したす。



䞀般化



䞊蚘のすべおの情報を簡単に芁玄するず、いく぀かのヒントずルヌルを策定できたす。









おわりに



この蚘事から䜕か新しいこずを孊び、シリアラむれヌションの問題の玠晎らしい専門家になったこずを願っおいたす。䞊蚘のヒントずルヌルを順守するこずで、デバッグに費やす時間を短瞮し、自分自身や他の開発者がクラスで䜜業しやすくなりたす。たた、PVS-Studioアナラむザヌを䜿甚するず、さらに簡単になり、゚ラヌが発生した盎埌に特定できたす。



远加情報











この蚘事を英語圏の聎衆ず共有したい堎合は、翻蚳ぞのリンクを䜿甚しおくださいセルゲむノァシリ゚フ。 シリアル化で䜜業するずきに自分の足で撃たない方法。



蚘事を読んで質問がありたすか
倚くの堎合、蚘事には同じ質問が寄せられたす。 ここで回答を集めたした PVS-Studioバヌゞョン2015に関する蚘事の読者からの質問ぞの回答 。 リストをご芧ください。




All Articles