Ответ 1
Позвольте мне объяснить это с помощью примера из самой XNA:
Конструктор ContentManager
принимает IServiceProvider
. Затем он использует IServiceProvider
для получения IGraphicsDeviceService
, который он, в свою очередь, использует для получения GraphicsDevice
, на который он загружает такие вещи, как текстуры, эффекты и т.д.
Нельзя взять Game
- потому что этот класс полностью необязателен (и находится в зависимой сборке). Он не может принимать GraphicsDeviceManager
(обычно используемая реализация IGraphicsDeviceService
), потому что, например, Game
является необязательным вспомогательным классом для настройки GraphicsDevice
.
Невозможно принять GraphicsDevice
напрямую, потому что вы можете создать ContentManager
до создания GraphicsDevice
(это именно то, что делает класс Game
по умолчанию). Таким образом, он получает услугу, чтобы позднее получить графическое устройство.
Теперь вот настоящий кикер: Он может принимать IGraphicsDeviceService
и использовать это напрямую. НО: что, если в какой-то момент в будущем команда XNA добавит (например) класс AudioDevice
, от которого зависят некоторые типы контента? Затем вам придется изменить подпись метода конструктора ContentManager
, чтобы взять IAudioDeviceService
или что-то еще, что приведет к поломке стороннего кода. Имея поставщика услуг, вы избегаете этой проблемы.
На самом деле вам не нужно ждать, когда команда XNA добавит новые типы контента, требующие общих ресурсов. Когда вы пишете пользовательский ContentTypeReader
, вы можете получить доступ к IServiceProvider
из менеджера контента и запросить его за любое обслуживание, которое вам нравится - даже свое! Таким образом, ваши пользовательские типы контента могут использовать тот же механизм, что и используемые в нем типы графических объектов класса XNA, без необходимости знать код XNA о них или о необходимых им услугах.
(И наоборот, если вы никогда не загружаете графические типы с помощью ContentManager
, вам никогда не придется предоставлять ему услугу графического устройства.)
Это, конечно, хорошо и хорошо для библиотеки, такой как XNA, которая должна быть обновляемой без нарушения стороннего кода. Особенно для чего-то вроде ContentManager
, которое расширяется третьими лицами.
Тем не менее: Я вижу много людей, работающих вокруг, используя DrawableGameComponent
, обнаружив, что вы не можете легко получить в нем общий SpriteBatch
и, таким образом, создаете какой-то sprite-batch- сервис, чтобы передать это. Это намного сложнее, чем вам нужно для игры, которая, как правило, не нуждается в проверке версий, сборочной зависимости или сторонних требований к расширяемости. Просто потому, что Game.Services
существует, не означает, что вы должны его использовать! Если вы можете передать вещи (например, экземпляр SpriteBatch
) непосредственно - просто сделайте это - это намного проще и понятнее.