Подтвердить что ты не робот

Класс, объявленный внутри другого класса в С#

Я работаю над некоторым устаревшим кодом и сталкиваюсь с тем, о чем я не уверен. У нас есть class y, который объявлен внутри другого class x. class y используется только внутри class x, но мой вопрос в том, почему бы вам не создать отдельный файл класса и не поставить там class y вместо того, чтобы объявить его внутри class x? Разве это не нарушает ООП или это просто вопрос стиля, поскольку он используется только внутри этого класса. Я рефакторинг некоторых из этого кода, и моя первая реакция будет заключаться в том, чтобы отделить class y от него в собственном файле.

namespace Library
{
   public class x
   {
      // methods, properties, local members of class x

      class y
      {
         // methods, properties, local members of class y
      }
   }
}
4b9b3361

Ответ 1

Вы создаете внутренний класс, потому что он используется только в пределах класса x и он логически подходит для факторинга/архитектуры класса x.

Класс y также может быть посвящен в детали реализации класса x, которые не должны быть известны общественности.

Ответ 2

Это имеет последствия для разрешений. Верхний уровень "класс y" будет "внутренним", однако здесь "y" является закрытым для "x". Этот подход полезен для деталей реализации (например, строк кеша и т.д.). Аналогично, y имеет доступ ко всем частным состояниям x.

Есть также последствия с дженериками; x<T>.y является общим "из T", унаследованным от внешнего класса. Вы можете увидеть это здесь, где Bar имеет полное использование T - и обратите внимание, что любые статические поля Bar ограничены в пределах T.

class Foo<T> {
    void Test(T value) {
        Bar bar = new Bar();
        bar.Value = value;
    }
    class Bar {
        public T Value { get; set; }
    }
}

Часто люди неправильно думают, что им нужно определить Bar как Bar<T> - это теперь (эффективно) вдвойне общее - т.е. Foo<TOld, T> - где TOld является (теперь недоступным) T из Foo<T>, Так что не делай этого! Или, если вы хотите, чтобы он был дважды родовым, выберите разные имена. К счастью, компилятор предупреждает вас об этом...

Ответ 3

Этот код отлично подходит по той причине, что вы указали - "класс y используется только внутри класса x". Это вложенные типы, и одно из рекомендаций по их использованию состоит в том, что вложенные типы должны быть тесно связаны с их типом объявления и не должны использоваться в качестве тип общего назначения. Таким образом, вложенный класс неприемлем для других классов, но все же позволяет вам следовать объектно-ориентированным принципам.

Ответ 4

Я думаю, что это нормально, если только содержащийся класс используется только как утилита. Я использую эту конструкцию, например, для определения сложных типов возвращаемых данных для частных методов.

Ответ 5

Я просто просмотрел код, который я обновляю (и я изначально написал), и удалил все вложенные классы. К сожалению, я изначально использовал вложенный класс вне класса, в котором он был определен. Перемещение вложенных классов внесло для меня огромное значение, потому что изначально у меня был плохой дизайн.

Если Y используется только в X и никогда не будет использоваться вне X, я бы сказал, держите его там

Ответ 6

Позвольте мне привести пример использования вложенных классов, которые могут уточнить, когда такая архитектура подходит. Недавно мне нужно было создать таблицу HTML, вытащив выбранные столбцы из таблицы данных и "развернув" их, чтобы строки стали столбцами и наоборот. В моем случае были две основные операции: поворот данных и создание некоторого довольно сложного вывода (я не просто показывал данные: каждая строка столбца/таблица данных подчинялась операциям для извлечения заголовка, генерированию тегов изображений, настройке ссылок, и т.д., поэтому использование SQL Pivot было не совсем правильным).

После первоначальной попытки создать один класс для выполнения всего этого, я понял, что большая часть данных/методов попала в три разных раздела: обработка заголовков, обработка строк и поворот. Таким образом, я решил, что лучшим подходом будет инкапсуляция логики для "заголовка" и "строки" в отдельные вложенные классы. Это позволило мне отделить данные, хранящиеся в каждой строке, и запрограммировать операции поворота очень чисто (вызов отдельного объекта строки для каждого столбца в вашей таблице данных). По завершении операций поворота я сгенерировал вывод, вызвав объект заголовка, а затем каждый объект строки, в свою очередь, чтобы генерировать свой вывод обратно в основной класс.

Отдельные классы не были подходящими, потому что A) вложенным классам нужны некоторые данные из мастер-класса, а B) обработка была очень конкретной и не была полезной в других местах. Просто программирование одного большого класса было просто беспорядочным из-за путаницы вокруг таких терминов, как "столбец" и "строка", которые отличались в зависимости от того, говорили ли вы о данных или выходе HTML. Кроме того, это была необычная работа в том, что я создавал HTML в своем бизнес-классе, поэтому я хотел разделить чистую бизнес-логику с поколением пользовательского интерфейса. В конце концов, вложенные классы обеспечивали идеальный баланс, а затем инкапсуляцию и обмен данными.

Ответ 7

Вы все равно можете реорганизовать свой класс y в другой файл, но используйте класс parial. Преимущество этого заключается в том, что у вас все еще есть один класс для каждого файла и у него нет проблем с рефакторингом перемещения объявления за пределами класса x.

например. у вас может быть файл кода: x.y.cs, который будет выглядеть примерно как

partial class X
{
    class Y
    {
        //implementation goes here
    }
}