# 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.