通过依赖注入访问便携式类库(PCL)中的平台特定功能(DI)

3856456237_f05ebd2602_o

便携式类库(PCL)允许开发人员通过多个设备,平台和运行时环境共享C#,F#和VB代码,例如.NET,XAMARIN或Windows Store应用程序。在此前一篇文章中,您可以看到如何编写便携式业务逻辑并将其与各种平台集成。但是,如果你真的想使用其他方式来说,那么何时会说GPS位置,文件系统等。那么?这正是他的帖子我们将看出以下主题:

  • 使用界面分离和依赖性反转对我们的青睐
    • 在PCL中的界面
    • 在平台上实现
  • 在运行时将实现注入PCL
  • 通过MVVM光使依赖关系的分辨率

所以让我们来吧!

利用依赖注入我们的青睐

记住 坚硬的?好吧,它能够完全针对模式的字母立刻,我们将使用它来解决我们的“我将如何使用平台特定的特征跨平台”模式。 PCL代码是平台独立的,因此可以在多个平台上使用,因此我们希望将所有业务逻辑附近放入PCL中。进一步通过接口访问具体类实现,我们可以在PCL中定义一个接口,并在特定于平台项目中创建它的具体实现。

pcldioverview.

依赖性注入动作

例如,假设我们要为每个平台显示当前的操作系统版本,这是一个非常平台的特定功能。要访问PLC中的此类信息,我们首先在PCL中定义一个界面,该接口描述了执行必须实施的合同:

public interface ISystemInformationHandler
{
    string OSVersion { get; }
}

在具体平台中,我们可以继承接口并实现调用特定于平台API的处理程序(您看到的android实现的以下):

internal class SystemInformationHandler:ISystemInformationHandler
{
    #region Implementation of ISystemInformationHandler

    //public string OSVersion => System.Environment.OSVersion.ToString();
    public string OSVersion => $"安卓 {Android.OS.Build.VERSION.SdkInt} {Android.OS.Build.VERSION.Release}";

    #endregion
}

现在在PCL中,我们可以具有例如需要处理程序来显示信息的视图模型的类。

public class MainViewModel : ViewModelBase
{
    private readonly ISystemInformationHandler _systemInformationHandler;

    public MainViewModel(ISystemInformationHandler systemInformationHandler)
    {
        if (systemInformationHandler == null) throw new ArgumentNullException(nameof(systemInformationHandler));
        _systemInformationHandler = systemInformationHandler;
    }

    public string OSVersion => _systemInformationHandler.OSVersion;
}

视图模型需要作为参数参数的一个实例 iosversionHandler. 界面。所以,当我们创建一个实例时 MainViewModel. 在平台项目中,我们可以简单地创建一个接口的实例并在创建它时将其传递到视图模型中。

var mainViewModel = new MainViewModel(new SystemInformationHandler());

并收到以下输出。安卓:

使用MVVM灯越过平台依赖性分辨率

现在通过手解决所有这些依赖性,随着时间的推移可以变得非常乏味。您可能已经注意到我正在使用MVVM灯,配有一个名为的轻量级依赖注入容器 简单的IOC。让我们看看我们如何使用此组件来进一步简化我们的跨平台开发工作。

**注意:**对于MVVM LIGH的简介,请参阅此博客文章 安卓 或者 iOS. 让你开始基础知识。

在pcl中我们有 ViewModellocator.cs. 这定义了所使用的所有实例,但没有平台特定的分辨率。

public class ViewModelLocator
{
    public ViewModelLocator()
    {
        ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

        if (ViewModelBase.IsInDesignModeStatic)
        {
            // Create design time view services and models
            SimpleIoc.Default.Register<ISystemInformationHandler, SystemInformationHandlerStub>();
        }

        SimpleIoc.Default.Register<MainViewModel>();
    }

    public MainViewModel Main
    {
        get
        {
            return ServiceLocator.Current.GetInstance<MainViewModel>();
        }
    }
}

在每个平台上,我们现在扩展定位器并注册平台特定的类I.E.Teptor for接口。

internal class Locator : ViewModelLocator
{
    private static readonly Lazy<Locator> _locator = new Lazy<Locator>(() => new Locator(), LazyThreadSafetyMode.PublicationOnly);
    public static Locator Instance => _locator.Value;

    private Locator()
    {
        SimpleIoc.Default.Register<ISystemInformationHandler, SystemInformationHandler>();
    }
}

现在我们可以简单地请求视图模型的实例(每个默认值的MVVM灯仅为每个注册的类创建一个实例)并使用它。在Android,这将看起来像这样 MainActivity.cs.:

[Activity(Label = "PclDISample.Droid", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity
{
    #region UI Controls

    private TextView OSVersion => FindViewById<TextView>(Resource.Id.OSVersion);

    #endregion

    private MainViewModel VM => Locator.Instance.Main;

    protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);

        // Set our view from the "main" layout resource
        SetContentView(Resource.Layout.Main);

        // Get our button from the layout resource,
        // and attach an event to it
        OSVersion.Text = VM.OSVersion;

        var mainViewModel = new MainViewModel(new SystemInformationHandler());
    }
}

在Windows 10中,我们可以简单地设置 datacontext. accordingly in XAML:

<Page
    x:Class="PclDISample.UWP.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:PclDISample"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  DataContext="{Binding Source={StaticResource Locator}, Path=Main}"
    mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <TextBlock Text="{Binding OSVersion}" VerticalAlignment="Center" HorizontalAlignment="Center" Style="{StaticResource TitleTextBlockStyle}"></TextBlock>
    </Grid>
</Page>

正如您可以看到一切都在简单的情况下注册 控制反转 MVVM光的容器(IOC)将自动执行所有依赖性分辨率。如果缺少依赖项,则会在运行时抛出异常(不是 在编译期间),因此确保要测试所有视图,用户控制等程序正确加载。

结论

在此帖子中,您可以看到如何使用依赖项注入来提供平台特定功能,以跨平台代码在PCL中跨平台代码而不创建任何循环依赖性错误。通过在PCL中使用接口并在运行时注入混凝土实现,我们可以创建通过通用定义接口提供平台特定功能的薄包装。最后,我们看到了如何使用MVVM光来创建一个更可管理和更易于管理的依赖性解决方案与简单的IOC定位器。

您可以找到完整的样本 GitHub..

非常感谢 Laurent Bugnion. 创造者MVVM灯。

Updated: