Внедрение зависимостей в .NET MAUI. Вызов кода платформы

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

Например, создадим новую реализацию сервиса ILogger так, чтобы в Android и Windows в лог записывались разные строки. На данный момент структура проекта выглядит следующим образом:

Допустим, мы захотим, чтобы в каждой строке лога прописывалось название операционной системы в которой запущено приложение. Сделать это можно двумя способами:

  1. использовать условную компиляцию
  2. использовать разделяемые классы и методы

Рассмотрим оба этих способа.

Вызов кода платформы с использованием разделяемых классов и методов

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

Определение сервиса

На данный момент, в нашем приложении уже определен сервис ILogger, который располагается в корне проекта и выглядит следующим образом:

public interface ILogger
{
    public void WriteLine(string message);
}

Вообще, общепринято размещать сервисы в папке Services проекта, но это не обязательное условие. Теперь создадим разделяемый класс, который будет определять сигнатуру метода WriteLine():

public partial class FileLoggerCrossPlatform : ILogger
{
    const string FILE_NAME = "Log.txt";
    private readonly DateTime _currentTime;

    private string fileName;

    public string FileName
    {
        get
        {
            return fileName;
        }
        set
        {
            fileName = value;
        }
    }

    private readonly string _newLine = Environment.NewLine;


    public partial void WriteLine(string message);
}

Здесь мы также определили те поля и свойства, которые будут иметь одно и то же значение во всех платформах. Теперь наша задача заключается в том, чтобы создать разделяемые классы, реализующие метод WriteLine() для каждой платформы.

Одно из важных условий реализации заключается в том, чтобы все классы располагались в одном пространстве имен. Например, сейчас класс FileLoggerCrossPlatform расположен в пространстве имен MauiApp23, следовательно и все другие разделяемые классы должны располагаться в этом пространстве имен.

Реализация сервиса для Windows

Создадим в папке Platform/Windows класс:

namespace MauiApp23
{
    public partial class FileLoggerCrossPlatform
    {

        public FileLoggerCrossPlatform() 
        {
            fileName = FILE_NAME;
        }

        public partial void WriteLine(string message)
        {
            File.AppendAllText(fileName, $"[Windows][{_currentTime}] - {message}{_newLine}");
        }
    }
}

Теперь можно зарегистрировать реализацию сервиса, запустить приложение в Windows и убедиться, что лог всё также продолжает записываться:

[Windows][01.01.0001 0:00:00] - Clicked 1 time

Перейдем к аналогичной реализации сервиса в Android.

Реализация сервиса для Android

Также добавляем разделяемый класс в папку Platforms/Android:

namespace MauiApp23
{
    public partial class FileLoggerCrossPlatform
    {

        public FileLoggerCrossPlatform()
        {
            fileName = Path.Combine(FileSystem.CacheDirectory, FILE_NAME);
        }

        public partial void WriteLine(string message)
        {
            File.AppendAllText(fileName, $"[Android][{_currentTime}] - {message}{_newLine}");
        }
    }
}

Обратите внимание на то, что у разделяемого класса в Android немного изменился конструктор — лог приложения будет храниться в папке кэша приложения. Теперь можно запустить приложение на любом поддерживаемом устройстве Android и убедиться, что оно работает без ошибок.

Когда использовать способ реализации сервиса на основе разделяемых классов и методов

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

Вызов кода платформы с использованием условной компиляции

Для управления условной компиляцией используются четыре директивы препроцессора.

  • #if: открывает условную компиляцию, где код компилируется, только если определен указанный символ.
  • #elif: закрывает предыдущую условную компиляцию и открывает новую на основе того, определен ли указанный символ.
  • #else: закрывает предыдущую условную компиляцию и открывает новую, если указанный символ не определен.
  • #endif: закрывает предыдущую условную компиляцию.

Для управления условной компиляцией в .NET MAUI уже определены символы, соответствующие определенной операционной системе. Перепишем нашу реализацию сервиса, используя символы условной компиляции. Для этого удалите разделяемые классы из папок Platform/Windows и Platform/Android, а класс FileLoggerCrossPlatform в корне проекта перепишите следующим образом:

namespace MauiApp23
{
    public class FileLoggerCrossPlatform : ILogger
    {
        const string FILE_NAME = "Log.txt";
        private readonly DateTime _currentTime;

        private string fileName;

        public string FileName
        {
            get
            {
                return fileName;
            }
            set
            {
                fileName = value;
            }
        }

        private readonly string _newLine = Environment.NewLine;


        public FileLoggerCrossPlatform()
        {
           #if ANDROID
           fileName = Path.Combine(FileSystem.CacheDirectory, FILE_NAME);
           #else
            fileName = FILE_NAME;
           #endif
        }

        public void WriteLine(string message)
        {
           #if ANDROID
           File.AppendAllText(fileName, $"[Android][{_currentTime}] - {message}{_newLine}");
           #else
           File.AppendAllText(fileName, $"[Windows][{_currentTime}] - {message}{_newLine}");
           #endif
        }
    }
}

Здесь мы использовали условную компиляцию для определения значения поля fileName и при записи строки в лог. Можно снова запустить приложение в разных операционных системах и убедиться в его работоспособности.

Когда использовать способ реализации сервиса с использованием условной компиляции

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

Итого

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

Подписаться
Уведомить о
guest
0 Комментарий
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии