Избегайте не только для чтения статических полей - неизменяемость NDepend - PullRequest
1 голос
/ 14 октября 2019

Я использую NDepend для анализа кода и получил это предупреждение:

https://www.ndepend.com/default-rules/NDepend-Rules-Explorer.html?ruleid=ND1901#!

Это правило предупреждает о статических полях, которые не объявлены только для чтения.

В объектно-ориентированном программировании естественным артефактом для хранения состояний, которые могут быть изменены, являются поля экземпляров. Такие изменяемые статические поля создают путаницу относительно ожидаемого состояния во время выполнения и ухудшают тестируемость кода, поскольку одно и то же изменяемое состояние повторно используется для каждого теста.

Мой код выглядит следующим образом:

using Cosmonaut;
using Microsoft.Azure.Documents.Client;
using System.Configuration;
using LuloWebApi.Entities;


namespace LuloWebApi.Components
{
    /// <summary>
    /// Main class that encapsulates the creation of instances to connecto to Cosmos DB
    /// </summary>
    public sealed class CosmosStoreHolder
    {
        /// <summary>
        /// Property to be initiated only once in the constructor (singleton)
        /// </summary>
        private static CosmosStoreHolder instance = null;

        /// <summary>
        /// To block multiple instance creation
        /// </summary>
        private static readonly object padlock = new object();

        /// <summary>
        /// CosmosStore object  to get tenants information
        /// </summary>
        public Cosmonaut.ICosmosStore<SharepointTenant> CosmosStoreTenant { get; }

        /// <summary>
        /// CosmosStore object  to get site collection information
        /// </summary>
        public Cosmonaut.ICosmosStore<SiteCollection> CosmosStoreSiteCollection { get; }

        /// <summary>
        /// CosmosStore object  to get page templates information
        /// </summary>
        public Cosmonaut.ICosmosStore<PageTemplate> CosmosStorePageTemplate { get; }

        /// <summary>
        /// CosmosStore object  to get pages information
        /// </summary>
        public Cosmonaut.ICosmosStore<Page> CosmosStorePage { get; }

        /// <summary>
        /// CosmosStore object  to get roles information
        /// </summary>
        public Cosmonaut.ICosmosStore<Role> CosmosStoreRole { get; }

        /// <summary>
        /// CosmosStore object  to get clients information
        /// </summary>
        public Cosmonaut.ICosmosStore<Client> CosmosStoreClient { get; }

        /// <summary>
        /// CosmosStore object  to get users information
        /// </summary>
        public Cosmonaut.ICosmosStore<User> CosmosStoreUser { get; }

        /// <summary>
        /// CosmosStore object  to get partners information
        /// </summary>
        public Cosmonaut.ICosmosStore<Partner> CosmosStorePartner { get; }

        /// <summary>
        /// CosmosStore object  to get super administrators information
        /// </summary>
        public Cosmonaut.ICosmosStore<SuperAdministrator> CosmosStoreSuperAdministrator { get; }

        /// <summary>
        /// Constructor
        /// </summary>
        CosmosStoreHolder()
        {

            CosmosStoreSettings settings = new Cosmonaut.CosmosStoreSettings(ConfigurationManager.AppSettings["database"].ToString(),
                 ConfigurationManager.AppSettings["endpoint"].ToString(),
                 ConfigurationManager.AppSettings["authKey"].ToString());

            settings.ConnectionPolicy = new ConnectionPolicy
            {
                ConnectionMode = ConnectionMode.Direct,
                ConnectionProtocol = Protocol.Tcp
            };


            CosmosStoreTenant = new CosmosStore<SharepointTenant>(settings);
            CosmosStoreSiteCollection = new CosmosStore<SiteCollection>(settings);
            CosmosStorePageTemplate = new CosmosStore<PageTemplate>(settings);
            CosmosStorePage = new CosmosStore<Page>(settings);
            CosmosStoreRole = new CosmosStore<Role>(settings);
            CosmosStoreClient = new CosmosStore<Client>(settings);
            CosmosStoreUser = new CosmosStore<User>(settings);
            CosmosStorePartner = new CosmosStore<Partner>(settings);
            CosmosStoreSuperAdministrator = new CosmosStore<SuperAdministrator>(settings);
        }

        /// <summary>
        /// Instance access, singleton
        /// </summary>
        public static CosmosStoreHolder Instance
        {
            get
            {
                lock (padlock)
                {
                    if (instance == null)
                    {
                        instance = new CosmosStoreHolder();
                    }
                    return instance;
                }
            }
        }
    }
}

Однако я не уверен, как исправить это предупреждение.

1 Ответ

6 голосов
/ 14 октября 2019

Это руководство, а не жесткое правило. Обычно, статические поля, не предназначенные только для чтения, трудно понять. Но в этом случае вы выполняете отложенную загрузку с отложенной загрузкой, так что ... lock и mutate - это действительно один из способов достижения этого без преждевременной загрузки.

Итак, прагматическое исправление:просто проигнорируйте / отмените предупреждение


Другой подход, однако, состоит в том, чтобы переместить поле в другой тип , где оно равно только для чтения, и полагаться на отложенноеСемантика .cctor:

public static CosmosStoreHolder Instance {
   [MethodImpl(MethodImplOptions.NoInlining)]
   get => DeferredHolder.Instance;
}

private static class DeferredHolder {
    internal static readonly CosmosStoreHolder Instance = new CosmosStoreHolder();
}

Тогда вам даже не понадобится семантика блокировки (.cctor справится с этим для вас).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...