Класс объявлен внутри другого класса в C # - PullRequest
47 голосов
/ 26 марта 2009

Я работаю над устаревшим кодом и наткнулся на то, в чем я не уверен. У нас есть 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
      }
   }
}

Ответы [ 7 ]

59 голосов
/ 26 марта 2009

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

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

20 голосов
/ 26 марта 2009

Это имеет значение разрешений. «Класс 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>. Так что не делай этого! Или, если вы хотите , чтобы он был двунаправленным, выберите другие имена. К счастью, компилятор предупреждает вас об этом ...

7 голосов
/ 26 марта 2009

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

2 голосов
/ 26 марта 2009

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

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

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

2 голосов
/ 26 марта 2009

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

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

2 голосов
/ 26 марта 2009

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

1 голос
/ 26 марта 2009

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

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

partial class X
{
    class Y
    {
        //implementation goes here
    }
} 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...