Как создать вложенную модель, сохраняя при этом внутренний класс закрытым?

#c# #api #oop #encapsulation #access-modifiers

Вопрос:

Я хочу инкапсулировать класс фильтра в свою модель выбора фильтра, чтобы фильтр не мог быть создан сам по себе. Однако, пытаясь установить свойство для доступа к списку, я получаю эту ошибку:

Несогласованная доступность: тип свойства менее доступен, чем свойство

 public class FilterSelection
    {

        public List<Filter> List { get; set; }

        public FilterSelection()
        {
            List = new List<Filter>();
        }


        private class Filter
        {
            public string CustomFilterName { get; set; }
            public string workBook { get; set; }
        }
    }
 

Комментарии:

1. Вы не можете предоставить свойство коду, который может использовать ваш класс, не раскрыв также тип этого свойства. Другими словами, если вы собираетесь позволить моему коду создать выбор фильтра и, как таковой, вы собираетесь предоставить мне доступ к «Списку» (я бы рекомендовал лучшее название), если «Список» — это набор объектов «Фильтра», какая польза от них мне, если я знаю, что такое «Фильтр»? Таким образом, либо класс «Фильтр» должен быть общедоступным, либо свойство «Список» должно быть закрытым. В качестве альтернативы вы можете сделать оба «внутренними», если вы просто хотите использовать их в своем классе выбора фильтров, не раскрывая его.

2. Определите открытый интерфейс и позвольте вашему классу наследовать от него и объявить вашего члена списка<интерфейс> — например. <интерфейс> dotnetfiddle.net/1pSjrT

3. Отметьте List свойство private set; Помните, добавление и удаление элементов из списка по-прежнему является get операцией, даже если вы вносите изменения: вы «получаете» ссылку на объект, а затем используете ссылку для вызова функции-члена объекта «Add ()».

Ответ №1:

Доступность свойства и типа должна быть согласованной (или, по крайней мере, свойство должно иметь меньшую или равную доступность для типа).

Вариант 1 — сделайте свойство и тип доступными для любого кода, который ссылается на ваш класс:

 public class FilterSelection
    {

        public List<Filter> List { get; set; }

        public FilterSelection()
        {
            List = new List<Filter>();
        }


        public class Filter
        {
            public string CustomFilterName { get; set; }
            public string workBook { get; set; }
        }
    }
 

Вариант 2 — не разрешайте доступ ни к свойству, ни к классу, за исключением конструктора(ов) вашего класса.

 public class FilterSelection
    {

        private List<Filter> List { get; set; }

        public FilterSelection()
        {
            List = new List<Filter>();
        }


        private class Filter
        {
            public string CustomFilterName { get; set; }
            public string workBook { get; set; }
        }
    }
 

Вариант 3 — Сделайте класс и свойство доступными для любого класса в этой сборке, но не за пределами сборки

 public class FilterSelection
    {

        internal List<Filter> List { get; set; }

        public FilterSelection()
        {
            List = new List<Filter>();
        }


        internal class Filter
        {
            public string CustomFilterName { get; set; }
            public string workBook { get; set; }
        }
    }
 

Вариант 4 — сделайте вашу собственность и класс доступными для вашего класса и любого класса, который наследует ваш класс

 public class FilterSelection
    {

        protected List<Filter> List { get; set; }

        public FilterSelection()
        {
            List = new List<Filter>();
        }


        protected class Filter
        {
            public string CustomFilterName { get; set; }
            public string workBook { get; set; }
        }
    }
 

Комментарии:

1. В настоящее время я работаю над веб-API, и это технический директор. Если для фильтра установлено значение public/internal, это будет означать, что фильтр можно создать без выбора фильтра. И установка его на защищенный/закрытый будет означать, что я не могу получить доступ к свойству списка с уровня контроллера или сервиса. Я хочу, чтобы мой класс фильтра был связан с выбором фильтра и больше нигде не использовался, если это возможно.