All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.sonar.plugins.csharp.S3925.html Maven / Gradle / Ivy

There is a newer version: 10.2.0.105762
Show newest version

Why is this an issue?

The ISerializable interface is the mechanism to control the type serialization process. If not implemented correctly this could result in an invalid serialization and hard-to-detect bugs.

This rule raises an issue on types that implement ISerializable without following the serialization pattern recommended by Microsoft.

Specifically, this rule checks for these problems:

  • The SerializableAttribute attribute is missing.
  • Non-serializable fields are not marked with the NonSerializedAttribute attribute.
  • There is no serialization constructor.
  • An unsealed type has a serialization constructor that is not protected.
  • A sealed type has a serialization constructor that is not private.
  • An unsealed type has an ISerializable.GetObjectData that is not both public and virtual.
  • A derived type has a serialization constructor that does not call the base constructor.
  • A derived type has an ISerializable.GetObjectData method that does not call the base method.
  • A derived type has serializable fields but the ISerializable.GetObjectData method is not overridden.

Classes that inherit from Exception are implementing ISerializable. Make sure the [Serializable] attribute is used and that ISerializable is correctly implemented. Even if you don’t plan to explicitly serialize the object yourself, it might still require serialization, for instance when crossing the boundary of an AppDomain.

This rule only raises an issue on classes that indicate that they are interested in serialization (see the Exceptions section). That is to reduce noise because a lot of classes in the base class library are implementing ISerializable, including the following classes: Exception, Uri, Hashtable, Dictionary<TKey,TValue>, DataSet, HttpWebRequest, Regex TreeNode, and others. There is often no need to add serialization support in classes derived from these types.

Exceptions

  • Classes in test projects are not checked.
  • Classes need to indicate that they are interested in serialization support by either
    1. Applying the [Serializable] attribute
    2. Having ISerializable in their base type list
    3. Declaring a serialization constructor
[Serializable]                                                                                 // 1.
public class SerializationOptIn_Attribute
{
}

public class SerializationOptIn_Interface : ISerializable                                      // 2.
{
}

public class SerializationOptIn_Constructor
{
    protected SerializationOptIn_Constructor(SerializationInfo info, StreamingContext context) // 3.
    {
    }
}

How to fix it

Make sure to follow the recommended guidelines when implementing ISerializable.

Code examples

Noncompliant code example

public class Bar
{
}

public class Foo : ISerializable // Noncompliant: serialization constructor is missing
                                 // Noncompliant: the [Serializable] attribute is missing
{
    private readonly Bar bar; // Noncompliant: the field is not marked with [NonSerialized]
}

public sealed class SealedFoo : Foo
{
    private int val; // Noncompliant: 'val' is serializable and GetObjectData is not overridden

    public SealedFoo()
    {
        // ...
    }

    public SealedFoo(SerializationInfo info, StreamingContext context) // Noncompliant: serialization constructor is not `private`
                                                                       // Noncompliant: serialization constructor does not call base constructor
    {
        // ...
    }
}

public class UnsealedFoo : Foo
{
    public UnsealedFoo()
    {
        // ...
    }

    public UnsealedFoo(SerializationInfo info, StreamingContext context) // Noncompliant: serialization constructor is not `protected`
        : base(info, context)
    {
        // ...
    }

    protected void GetObjectData(SerializationInfo info, StreamingContext context) // Noncompliant: GetObjectData is not public virtual
    {
        // Noncompliant: does not call base.GetObjectData(info, context)
    }
}

Compliant solution

public class Bar
{
}

[Serializable]
public class Foo : ISerializable // Compliant: the class is marked with [Serializable]
{
    [NonSerialized]
    private readonly Bar bar; // Compliant: the field is marked with [NonSerialized]

    public Foo()
    {
        // ...
    }

    protected Foo(SerializationInfo info, StreamingContext context) // Compliant: serialization constructor is present
    {
        // ...
    }

    public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        // ...
    }
}

[Serializable]
public sealed class SealedFoo : Foo
{
    private int val; // Compliant: 'val' is serializable and GetObjectData is overridden

    public SealedFoo()
    {
        // ...
    }

    private SealedFoo(SerializationInfo info, StreamingContext context) // Compliant: serialization constructor is `private`
        : base(info, context) // Compliant: serialization constructor calls base constructor
    {
        // ...
    }

    public override void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        base.GetObjectData(info, context);
        // ...
    }
}

[Serializable]
public class UnsealedFoo : Foo
{
    public UnsealedFoo()
    {
        // ...
    }

    protected UnsealedFoo(SerializationInfo info, StreamingContext context) // Compliant: serialization constructor is `protected`
        : base(info, context)
    {
        // ...
    }

    public virtual void GetObjectData(SerializationInfo info, StreamingContext context) // Compliant: GetObjectData is public virtual
    {
        base.GetObjectData(info, context); // Compliant: calls base.GetObjectData(info, context)
        // ...

    }
}

Resources

Documentation





© 2015 - 2024 Weber Informatics LLC | Privacy Policy