Поделиться через


Регистрация и разрешение класса Xamarin.Forms DependencyService

При использовании Xamarin.FormsDependencyService функции собственной платформы реализация платформы должна быть зарегистрирована в DependencyService, а затем разрешена из общего кода для их вызова.

Регистрация реализаций платформы

Реализации платформы должны быть зарегистрированы в DependencyService, чтобы платформа Xamarin.Forms могла их обнаруживать во время выполнения.

Регистрацию можно выполнить с помощью DependencyAttribute или методов Register и RegisterSingleton.

Внимание

Сборки выпуска проектов универсальной платформы Windows, использующие компиляцию в собственный код .NET, должны регистрировать реализации платформы с помощью методов Register.

Регистрация с помощью атрибута

Можно использовать DependencyAttribute, чтобы зарегистрировать реализацию платформы в DependencyService. Атрибут указывает, что заданный тип предоставляет конкретную реализацию интерфейса.

В следующем примере используется DependencyAttribute для регистрации реализации интерфейса IDeviceOrientationService для iOS.

using Xamarin.Forms;

[assembly: Dependency(typeof(DeviceOrientationService))]
namespace DependencyServiceDemos.iOS
{
    public class DeviceOrientationService : IDeviceOrientationService
    {
        public DeviceOrientation GetOrientation()
        {
            ...
        }
    }
}

В этом примере DependencyAttribute регистрирует DeviceOrientationService в DependencyService. Это приводит к регистрации конкретного типа с интерфейсом, который он реализует.

Аналогичным образом реализации интерфейса IDeviceOrientationService на других платформах должны быть зарегистрированы с помощью DependencyAttribute.

Примечание.

Регистрация с помощью DependencyAttribute выполняется на уровне пространства имен.

Регистрация с помощью метода

Вы можете использовать методы DependencyService.Register и RegisterSingleton, чтобы зарегистрировать реализацию платформы в DependencyService.

В следующем примере используется метод Register для регистрации реализации интерфейса IDeviceOrientationService для iOS.

[Register("AppDelegate")]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
    public override bool FinishedLaunching(UIApplication app, NSDictionary options)
    {
        global::Xamarin.Forms.Forms.Init();
        LoadApplication(new App());
        DependencyService.Register<IDeviceOrientationService, DeviceOrientationService>();
        return base.FinishedLaunching(app, options);
    }
}

В этом примере метод Register регистрирует конкретный тип DeviceOrientationService с интерфейсом IDeviceOrientationService. Таким же образом можно использовать перегрузку метода Register, чтобы зарегистрировать реализацию платформы в DependencyService.

DependencyService.Register<DeviceOrientationService>();

В этом примере Register регистрирует DeviceOrientationService в DependencyService. Это приводит к регистрации конкретного типа с интерфейсом, который он реализует.

Кроме того, можно зарегистрировать отдельный существующий экземпляр объекта с помощью метода RegisterSingleton:

var service = new DeviceOrientationService();
DependencyService.RegisterSingleton<IDeviceOrientationService>(service);

В этом примере метод RegisterSingleton регистрирует отдельный экземпляр объекта DeviceOrientationService с интерфейсом IDeviceOrientationService.

Аналогичным образом реализации интерфейса IDeviceOrientationService на других платформах можно зарегистрировать с помощью методов Register или RegisterSingleton.

Внимание

Регистрация с помощью методов Register и RegisterSingleton должна выполняться в проектах платформы до того, как функции, предоставляемые реализацией платформы, будут вызваны из общего кода.

Разрешение реализаций платформы

Реализации платформы необходимо разрешить до их вызова. Обычно это делается в общем коде с помощью метода DependencyService.Get<T>. Это также можно сделать с помощью метода DependencyService.Resolve<T>.

По умолчанию DependencyService разрешает только зависящие от платформы реализации с конструкторами без параметров. Однако в Xamarin.Forms можно внедрить метод разрешения зависимостей, который разрешает зависящие от платформы реализации с помощью контейнера внедрения зависимостей или фабричных методов. Такой подход позволяет разрешать зависящие от платформы реализации, имеющие конструкторы с параметрами. Дополнительные сведения см. в статье Разрешение зависимостей в Xamarin.Forms.

Внимание

Вызов реализации платформы, которая не была зарегистрирована с помощью DependencyService приведет к возникновению NullReferenceException.

Разрешение с помощью метода Get<T>

Метод Get<T> извлекает реализуемый платформой интерфейс T во время выполнения и:

  • либо создает его отдельный экземпляр;
  • либо возвращает отдельный существующий экземпляр, зарегистрированный с помощью DependencyService методом RegisterSingleton.

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

Следующий пример кода демонстрирует вызов метода Get<T> для разрешения интерфейса IDeviceOrientationService и последующего вызова его метода GetOrientation:

IDeviceOrientationService service = DependencyService.Get<IDeviceOrientationService>();
DeviceOrientation orientation = service.GetOrientation();

Этот код можно сократить до одной строки:

DeviceOrientation orientation = DependencyService.Get<IDeviceOrientationService>().GetOrientation();

Примечание.

По умолчанию метод Get<T> возвращает отдельный экземпляр интерфейса T, реализуемого платформой. Хотя это можно изменить. Дополнительные сведения см. в разделе Управлении временем существования разрешенных объектов.

Разрешение с помощью метода Resolve<T>

Метод Resolve<T> извлекает интерфейс T, реализуемый платформой во время выполнения, используя метод разрешения зависимостей, который внедряется в Xamarin.Forms с помощью класса DependencyResolver. Если метод разрешения зависимостей не был внедрен в Xamarin.Forms, метод Resolve<T> переключается на вызов метода Get<T>, чтобы извлечь реализацию платформы. Дополнительные сведения о внедрении метода разрешения зависимостей в Xamarin.Forms см. в статье о разрешении зависимостей в Xamarin.Forms.

Следующий пример кода демонстрирует вызов метода Resolve<T> для разрешения интерфейса IDeviceOrientationService и последующего вызова его метода GetOrientation:

IDeviceOrientationService service = DependencyService.Resolve<IDeviceOrientationService>();
DeviceOrientation orientation = service.GetOrientation();

Этот код можно сократить до одной строки:

DeviceOrientation orientation = DependencyService.Resolve<IDeviceOrientationService>().GetOrientation();

Примечание.

Когда метод Resolve<T> переключается на вызов метода Get<T>, он по умолчанию возвращает отдельный экземпляр интерфейса T, реализуемого платформой. Хотя это можно изменить. Дополнительные сведения см. в разделе Управлении временем существования разрешенных объектов.

Управлении временем существования разрешенных объектов

По умолчанию класс DependencyService разрешает отдельную реализацию платформы. Таким образом, реализации платформы будут существовать в течение всего срока существования приложения.

Такое поведение определяется необязательным аргументом DependencyFetchTarget в методах Get<T> и Resolve<T>. Перечисление DependencyFetchTarget определяет два члена:

  • GlobalInstance, который возвращает отдельную реализацию платформы;
  • NewInstance, который возвращает новый экземпляр реализации платформы. После этого управление временем существования экземпляра реализации платформы передается приложению.

Методы Get<T> и Resolve<T> назначают DependencyFetchTarget.GlobalInstance свои необязательные аргументы, поэтому всегда разрешаются отдельные экземпляры реализаций платформы. Это поведение можно изменить так, чтобы создавались новые экземпляры реализаций платформы, указав DependencyFetchTarget.NewInstance в качестве аргументов в методах Get<T> и Resolve<T>.

ITextToSpeechService service = DependencyService.Get<ITextToSpeechService>(DependencyFetchTarget.NewInstance);

В этом примере DependencyService создает новый экземпляр реализации платформы для интерфейса ITextToSpeechService. Все последующие вызовы для разрешения ITextToSpeechService будут также создавать новые экземпляры.

В результате постоянного создания новых экземпляров реализации платформы управление временем существования экземпляров передается приложению. Следовательно, если вы подписаны на событие, определяемое в реализации платформы, вы должны отменить подписку на него, когда реализация платформы больше не требуется. Кроме того, это означает, что реализациям платформы может потребоваться реализация IDisposable и очистка своих ресурсов с помощью методов Dispose. Пример приложения демонстрирует этот сценарий с реализациями платформы TextToSpeechService.

Когда приложение завершает использование реализации платформы, реализующей IDisposable, оно должно вызывать реализацию Dispose объекта. Один из способов сделать это — воспользоваться инструкцией using.

ITextToSpeechService service = DependencyService.Get<ITextToSpeechService>(DependencyFetchTarget.NewInstance);
using (service as IDisposable)
{
    await service.SpeakAsync("Hello world");
}

В этом примере после вызова метода SpeakAsync инструкция using автоматически удаляет объект реализации платформы. Это приводит к вызову метода Dispose объекта, который выполняет необходимую очистку.

Дополнительные сведения о вызове метода Dispose объекта см. в статье Использование объектов, реализующих IDisposable.