Как исправить: избегайте статических полей, не предназначенных только для чтения

Я использую NDepend, и в следующем коде он обнаруживает этот запах кода.

Но если я добавлю только для чтения, он не скомпилируется.

namespace todo
{
    using System;
    using System.Collections.Generic;
    using System.Configuration;
    using System.Linq;
    using System.Linq.Expressions;
    using System.Threading.Tasks;
    using Microsoft.Azure.Documents;
    using Microsoft.Azure.Documents.Client;
    using Microsoft.Azure.Documents.Linq;

    public static class DocumentDBRepository<T> where T : class
    {
        private static readonly string DatabaseId = ConfigurationManager.AppSettings["database"];
        private static readonly string CollectionId = ConfigurationManager.AppSettings["collection"];
        private static DocumentClient client;

        public static async Task<T> GetItemAsync(string id)
        {
            try
            {
                Document document = await client.ReadDocumentAsync(UriFactory.CreateDocumentUri(DatabaseId, CollectionId, id));
                return (T)(dynamic)document;
            }
            catch (DocumentClientException e)
            {
                if (e.StatusCode == System.Net.HttpStatusCode.NotFound)
                {
                    return null;
                }
                else
                {
                    throw;
                }
            }
        }

        public static async Task<IEnumerable<T>> GetItemsAsync(Expression<Func<T, bool>> predicate)
        {
            IDocumentQuery<T> query = client.CreateDocumentQuery<T>(
                UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId),
                new FeedOptions { MaxItemCount = -1 })
                .Where(predicate)
                .AsDocumentQuery();

            List<T> results = new List<T>();
            while (query.HasMoreResults)
            {
                results.AddRange(await query.ExecuteNextAsync<T>());
            }

            return results;
        }

        public static async Task<Document> CreateItemAsync(T item)
        {
            return await client.CreateDocumentAsync(UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId), item);
        }

        public static async Task<Document> UpdateItemAsync(string id, T item)
        {
            return await client.ReplaceDocumentAsync(UriFactory.CreateDocumentUri(DatabaseId, CollectionId, id), item);
        }

        public static async Task DeleteItemAsync(string id)
        {
            await client.DeleteDocumentAsync(UriFactory.CreateDocumentUri(DatabaseId, CollectionId, id));
        }

        public static void Initialize()
        {
            client = new DocumentClient(new Uri(ConfigurationManager.AppSettings["endpoint"]), ConfigurationManager.AppSettings["authKey"]);
            CreateDatabaseIfNotExistsAsync().Wait();
            CreateCollectionIfNotExistsAsync().Wait();
        }

        private static async Task CreateDatabaseIfNotExistsAsync()
        {
            try
            {
                await client.ReadDatabaseAsync(UriFactory.CreateDatabaseUri(DatabaseId));
            }
            catch (DocumentClientException e)
            {
                if (e.StatusCode == System.Net.HttpStatusCode.NotFound)
                {
                    await client.CreateDatabaseAsync(new Database { Id = DatabaseId });
                }
                else
                {
                    throw;
                }
            }
        }

        private static async Task CreateCollectionIfNotExistsAsync()
        {
            try
            {
                await client.ReadDocumentCollectionAsync(UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId));
            }
            catch (DocumentClientException e)
            {
                if (e.StatusCode == System.Net.HttpStatusCode.NotFound)
                {
                    await client.CreateDocumentCollectionAsync(
                        UriFactory.CreateDatabaseUri(DatabaseId),
                        new DocumentCollection { Id = CollectionId },
                        new RequestOptions { OfferThroughput = 1000 });
                }
                else
                {
                    throw;
                }
            }
        }
    }
}

Предупреждающая строка:

private static DocumentClient client;

Как бы вы порекомендовали исправить это предупреждение NDepend?

Описание правила:

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

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

Дополнительные обсуждения этой темы можно найти здесь: http://codebetter.com/patricksmacchia/2011/05/04/back-to-basics-usage-of-static-members/


person Luis Valencia    schedule 01.06.2018    source источник
comment
он обнаруживает этот запах кода ? о_О   -  person SᴇM    schedule 01.06.2018
comment
Почему ваш client статичен? Это HttpClient?   -  person bommelding    schedule 01.06.2018
comment
это пример пакета космосдб при создании нового экземпляра БД   -  person Luis Valencia    schedule 01.06.2018
comment
Предпочтительно, я бы переписал код, чтобы он работал с внедрением зависимостей, чтобы DocumentDBRepository вводился требуемому вызывающему объекту вместо сохранения статического класса.   -  person user1672994    schedule 01.06.2018
comment
на самом деле хороший подход! Пользователь   -  person Luis Valencia    schedule 01.06.2018
comment
Да, моя первая мысль здесь заключается в том, что эта проблема исчезает, когда вы используете контейнер DI для подачи зависимостей, а не привязываете их время жизни к статическому свойству.   -  person spender    schedule 01.06.2018
comment
Ради MCVE: вы включили гораздо больше кода, чем необходимо для иллюстрации, попробуйте ограничить это   -  person Peter B    schedule 01.06.2018


Ответы (1)


Попробуйте перенести инициализацию в объявление:

private static readonly DocumentClient client = new DocumentClient( . . . . );
person Peter B    schedule 01.06.2018