【问题标题】:Net Core: Do Static Classes need ISerializable from SonarQube?Net Core:静态类需要来自 SonarQube 的 ISerializable 吗?
【发布时间】:2019-12-25 00:00:51
【问题描述】:

有人理解 Sonarqube 中的这个错误吗?我们想要实现一个网格需求维度——给定一些图片。 2 张图片是 1X2 网格,4 张图片是 2X2,6 张图片是 3X2,等等。Sonarqube 要求为这些简单的静态类实现 Serializable。我将如何解决这个问题,是否有必要?

当前代码:

public class CardDimensionRequirement:Dictionary<int, CardDimensionRequirementLine> 
{
    public void AddItem(int PictureCount, int Length, int Height, int BootstrapDimension)
    {
        base.Add(PictureCount, new CardDimensionRequirementLine(PictureCount, Length, Height, BootstrapDimension));
    }

    public int GetMaxKey()
    {
        return base.Keys.Max();
    }    
}

static class CardDimensionRequirementSpecs
{
    public static CardDimensionRequirement cardDimensionRequirementData;

    static CardDimensionRequirementSpecs()
    {
        //int PictureCount, int Length, int Height, int BootstrapDimension
        cardDimensionRequirementData = new CardDimensionRequirement();
        cardDimensionRequirementData.AddItem(1, 1, 1, 1);
        cardDimensionRequirementData.AddItem(2, 2, 1, 6);
        cardDimensionRequirementData.AddItem(3, 3, 1, 4);
        cardDimensionRequirementData.AddItem(4, 2, 2, 6);
        cardDimensionRequirementData.AddItem(5, 3, 2, 4);
        cardDimensionRequirementData.AddItem(6, 3, 2, 4);
    }
}

SonarQube 推荐:

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 rules raises an issue on types that implement ISerializable without following the serialization pattern recommended by Microsoft.

Specifically this rule checks for these problems:

The System.SerializableAttribute attribute is missing.
Non-serializable fields are not marked with the System.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 a 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 a ISerializable.GetObjectData method that does not call the base method.
A derived type has serializable fields but the ISerializable.GetObjectData method is not overridden.

Noncompliant Code Example
public class Foo : ISerializable // Noncompliant the [Serializable] attribute is missing
{
}
or

public class Bar
{
}

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

Compliant Solution
public class Bar
{
}

[Serializable]
public class Foo : ISerializable
{
    [NonSerialized]
    private readonly Bar bar;

    public Foo()
    {
        // ...
    }

    protected Foo(SerializationInfo info, StreamingContext context)
    {
        // ...
    }

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

[Serializable]
public sealed class SubFoo : Foo
{
    private int val;

    public SubFoo()
    {
        // ...
    }

    private SubFoo(SerializationInfo info, StreamingContext context)
        : base(info, context)
    {
        // ...
    }

    public override void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        base.GetObjectData(info, context);
        // ...
    }
}
Exceptions
Classes in test projects are not checked.

【问题讨论】:

  • 这可能是因为您的基类Dictionary&lt;TKey, TValue&gt; 实现了ISerializable 并应用了[Serializable],因此可能会出现此错误。尝试实现IDictionary&lt;int, CardDimensionRequirementLine&gt; 并将您的字典作为私有成员包含在其中,看看错误是否消失。
  • 另外,您是否需要通过BinaryFormatter 和/或数据合约序列化程序来序列化您的类型?
  • 嗨@dbc 你怎么知道Dictionary 实现了ISerializable?问题已解决!你记得在你的头上吗?随意放置答案,我可以给分,希望能够自学,您似乎忽略了Sonarqube解决方案,并找到了真正的解决方法,有时代码分析器不正确
  • 我可以写一个答案。一个问题:您最终是实现了ISerializable 还是直接实现了IDictionary&lt;int, CardDimensionRequirementLine&gt;
  • @dbc 第二个选项 IDictionary

标签: c# asp.net-core serialization .net-core sonarqube


【解决方案1】:

SonarQube 可能会给出该错误,因为您的基本类型 Dictionary&lt;TKey,TValue&gt;通过 ISerializable 接口实现自定义二进制序列化。鉴于您的基类型实现了自定义序列化,SonarQube 似乎假设您需要重写该自定义序列化以添加派生类型声明成员的序列化。

然而,你的类型没有声明它自己的字段或属性,因此没有任何特定的序列化。

那么,你有什么办法来解决这个问题?

如果您不关心二进制序列化并且不需要支持它,您可以采用decorator pattern 并实现IDictionary&lt;int, CardDimensionRequirementLine&gt;,而不是从Dictionary&lt;TKey,TValue&gt; 派生。然后,在CardDimensionRequirement 内部有一些私有字典来进行实际查找:

public class CardDimensionRequirement : IDictionary<int, CardDimensionRequirementLine>
{
    readonly Dictionary<int, CardDimensionRequirementLine> dictionary = new Dictionary<int, CardDimensionRequirementLine>();

    public void AddItem(int PictureCount, int Length, int Height, int BootstrapDimension)
    {
        Add(PictureCount, new CardDimensionRequirementLine(PictureCount, Length, Height, BootstrapDimension));
    }

    public int GetMaxKey()
    {
        return Keys.Max();
    }   

    #region IDictionary<int,CardDimensionRequirementLine> Members

    // Delegate everything to this.dictionary:

    public void Add(int key, CardDimensionRequirementLine value)
    {
        this.dictionary.Add(key, value);
    }

    // Remainder snipped

不要将类标记为[Serializable] 或实现ISerializable

这种实现的一个优点是切换到不同的字典,比如SortedDictionary&lt;int, CardDimensionRequirementLine&gt;,不会是一个重大变化。

如果您确实关心二进制序列化,您应该将您的类型标记为[Serializable],覆盖GetObjectData(),并引入您自己的streaming constructor,如下所示:

[Serializable]
public class CardDimensionRequirement : Dictionary<int, CardDimensionRequirementLine>
{
    public CardDimensionRequirement() : base() { }

    protected CardDimensionRequirement(SerializationInfo info, StreamingContext context)
        : base(info, context)
    {
        // Nothing to do since your class currently has no fields
    }

    public override void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        base.GetObjectData(info, context);
        // Deserialize fields here, if you ever add any.
    }

    // Remainder snipped

作为替代方案,由于您的 CardDimensionRequirement 实际上没有任何要记住的数据,您可以简单地使用任何旧的 Dictionary&lt;int, CardDimensionRequirementLine&gt; 并将您的方法实现为扩展方法:

public static class CardDimensionRequirementExtensions
{
    public static void AddItem(this IDictionary<int, CardDimensionRequirementLine> dictionary, int PictureCount, int Length, int Height, int BootstrapDimension)
    {
        if (dictionary == null)
            throw new ArgumentNullException();
        dictionary.Add(PictureCount, new CardDimensionRequirementLine(PictureCount, Length, Height, BootstrapDimension));
    }

    public static int GetMaxKey(this IDictionary<int, CardDimensionRequirementLine> dictionary)
    {
        if (dictionary == null)
            throw new ArgumentNullException();
        return dictionary.Keys.Max();
    }   
}

【讨论】:

  • 我的问题是为什么 SonarQube 不能自己解决这个问题。我有一个类文件,它只有 public class MyClass : Dictionary&lt;string, object&gt; {},没有方法,其他任何字段
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-21
相关资源
最近更新 更多