V3097. Possible exception: type marked by [Serializable] contains non-serializable members not marked by [NonSerialized].
Анализатор обнаружил подозрительный класс, декорированный атрибутом [Serializable] и имеющий члены несериализуемых типов (т.е. типов, которые сами не декорированы этим атрибутом). При этом, несериализуемые члены не помечены атрибутом [NonSerialized]. Наличие таких членов может, при использовании некоторых стандартных классов для сериализации, привести к возникновению исключения типа 'SerializationException' при попытке сериализации экземпляра данного класса.
Рассмотрим пример. Предположим, что у нас есть метод, выполняющий сериализацию и десериализацию объекта:
static void Foo(MemoryStream ms, BinaryFormatter bf, C1 obj)
{
bf.Serialize(ms, obj);
ms.Position = 0;
obj = (C1)bf.Deserialize(ms);
}
Имеются следующие определения классов 'C1' и 'NonSerializedClass':
sealed class NonSerializedClass { }
[Serializable]
class C1
{
private Int32 field1;
private NotSerializedClass field2;
}
При попытке сериализации экземпляра класса 'C1' возникнет исключение типа 'SerializationException', так как декорирование класса атрибутом [Serializable] подразумевает, что все поля будут сериализованы. Но тип поля 'field2' не сериализуем, что приведёт к возникновению исключения. Для решения проблемы поле 'field2' необходимо декорировать атрибутом [NonSerialized]. Тогда корректное определение класса 'C1' может выглядеть так:
[Serializable]
class C1
{
private Int32 field1;
[NonSerialized]
private NotSerializedClass field2;
}
Со свойствами ситуация несколько отличается. Рассмотрим пример ошибочного класса:
[Serializable]
class C2
{
private Int32 field1;
public NonSerializedClass Prop { get; set; }
}
К свойствам нельзя применить атрибут [NonSerialized]. Тем не менее, при попытке сериализовать такой класс, например, с использованием 'BinaryFormatter', будет сгенерировано исключение. Дело в том, что автоматически реализуемые свойства компилятором раскрываются в поле и методы получения значения этого свойства и, возможно, записи. В этом случае будет выполняться сериализация не самого свойства, а поля, сгенерированного компилятором. Эта ситуация аналогична описанному ранее примеру с полем.
Ошибку можно исправить, явно реализовав свойство через какое-то поле. Тогда корректный код будет выглядеть так:
[Serializable]
class C2
{
private Int32 field1;
[NonSerialized]
private NonSerializedClass nsField;
public NonSerializedClass Prop
{
get { return nsField; }
set { nsField = value; }
}
}
Взгляните на примеры ошибок, обнаруженных с помощью диагностики V3097. |