Я прочитал несколько статей о том, когда использовать вложенные классы, но ни одна из найденных мной статей не отвечает на мой конкретный вопрос.
В C # есть класс XmlReader, который предоставляет только метод Create (). Я предполагаю, что создание создает подкласс XmlReader. Если нет, то для этого примера предположим, что это так.
Рассмотрим эти отношения:
/// <summary>
/// Class to read information in a file on disk
/// </summary>
interface ILoad
{
/// <summary> Version number of the file </summary>
int Version {get;}
/// <summary> Content of the file </summary>
string Content {get;}
/// <summary> Full path to the file </summary>
string FullPath {get;}
}
/// <summary> Provides base loading functionality </summary>
class LoaderBase : ILoad
{
public int Version {get; protected set;}
public string Content {get; protected set;}
public string FullPath{get; protected set;}
/* Helpers omitted */
protected abstract void Load(string pathToFile);
public static LoaderBase Create(string pathToFile)
{
switch(Path.GetExtension(pathToFile))
{
// Select the correct loader based on the file extension and return
}
return null;//unknown file type
}
}
/// <summary> Base class functionality to load compiled files </summary>
public abstract class CompiledLoaderBase : LoaderBase
{
protected CompiledLoaderBase(string path)
{
Load(path);
}
protected override Load(string path)
{
/* read the file and create an XmlReader from it */
ReadVersionNumber(reader);
ReadContent(reader);
}
protected abstract void ReadVersionNumber(XmlReader reader);
protected abstract void ReadContent(XmlReader reader);
// Wish I could call this Create, but inherited a static Create method already
public static CompiledLoaderBase CreateCompiled(string path)
{
//Figure out which loader to create and return it
// ... Assume we figured out we need V1
return new CompiledLoaderV1(path);
}
// Here's the fun stuff!
protected class CompiledLoaderV1 : CompiledLoaderBase
{
public CompiledLoaderV1(string path)
: base(path)
{}
protected override ReadVersionNumber(XmlReader reader)
{ /* read the version number and store in Version */ }
protected override ReadContent(XmlReader reader)
{ /* read the content and store in Content */ }
}
// ... More classes with their own methods for reading version and content
}
Теперь я использовал вложенные классы, чтобы запретить пользователю напрямую создавать определенные загрузчики; они должны использовать один из методов Create * абстрактной базы. FxCop взорвал меня из-за этого, и я надеялся получить разъяснения относительно того, почему.
Он упомянул не использовать вложенные классы, а вместо этого пространства имен. Есть ли способ добиться этого с помощью пространств имен?
РЕДАКТИРОВАТЬ: В частности, сообщение: «NestedTypesShouldNotBeVisible». Решение: «Не вкладывайте тип CompiledLoaderBase + CompiledLoaderV1. Или измените его доступность, чтобы он не был виден извне». Информация: «Не используйте общедоступные, защищенные или защищенные внутренние вложенные типы в качестве способа группировки типов. Используйте для этой цели пространства имен. Есть очень ограниченные сценарии, в которых вложенные типы являются лучшим дизайном». Я считаю, что Джон Скит определил, что вы не можете добиться этого с помощью пространств имен. Я просто хотел убедиться, поскольку эта ошибка говорит о том, что существует ограниченное количество сценариев, в которых это лучший дизайн, поэтому, если есть лучший вариант, я открыт для идей: D
Также ему не нравилась цепочка виртуальных вызовов, вызываемая из конструктора. Есть причина для этого? Есть ли способ обойти это? РЕДАКТИРОВАТЬ: В частности, сообщение: «DoNotCallOverridableMethodsInConstructors». Решение: «CompiledLoaderV2.CompiledLoaderV2 (String)» содержит цепочку вызовов, которая приводит к вызову виртуального метода, определенного классом. Просмотрите следующий стек вызовов на предмет непредвиденных последствий »Информация:« Виртуальные методы, определенные в классе, не должны быть вызывается из конструкторов. Если производный класс переопределил метод, будет вызываться версия производного класса (до вызова конструктора производного класса) ». Я чувствую, что это могло быть проблемой, если бы подклассы что-то сделали в своих конструкторах, но поскольку они этого не делают, я не уверен, что это проблема. Есть ли лучший способ заставить классы загружаться определенным образом без использования абстрактных методов в конструкторе?
Большое спасибо за вашу помощь!