Позвольте мне объяснить это на примере самой 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
, и, таким образом, создавая какой-то сервис-спрайт чтобы передать это. Это намного сложнее, чем нужно для игры, в которой обычно не нужно беспокоиться о версиях, зависимости от сборки или сторонних расширениях. То, что существует Game.Services
, не означает, что вы должны его использовать! Если вы можете передавать вещи (например, SpriteBatch
экземпляр) напрямую - просто сделайте это - это намного проще и очевиднее.