來,Winform使用依賴注入!

來,Winform使用依賴注入!

關於依賴注入是什麼?依賴注入是一種具體的編碼技巧,對我來說最明顯的就是解決程式碼的耦合性。

最後更新 2022/4/22 上午7:21
AZRNG 鹏祥
預計閱讀 4 分鐘
分類
Winform
標籤
.NET Winform 依賴注入 IOC

站長:Winform 的分享文章不多,這個技術相對來說已經十分穩定了,該有的都有了,今天分享其他號寫的 Winform 依賴注入一文,希望做相關開發的朋友能有新的體會。

1. 介紹

關於依賴注入是什麼?依賴注入是一種具體的編碼技巧,對我來說最明顯的就是解決程式碼的耦合性。

2. 目的

ASP.NET Core 中本身容器已經建立好了,只需要往容器加入服務即可,但是在 Winform 中預設還是透過 new 的方式來進行操作的(雖然我已經升級成了 .Net6),最近在把一個開源專案進行增加自用的功能,然後我順便將原來的 .NET Framework 升級為 .NET Core,然後就想用依賴注入方式去試試了。

C/S 程式碼寫得少,如有不對,麻煩指正。

3. 操作

本文範例環境:VS2022、.Net6、Windows 表單應用程式

4. 準備

範例包含以下程式碼

  • 表單:Form1、Form2

  • Service:IUserservice、Userservice、IOrderService、OrderService

public interface IUserservice
{
    string GetName();
}

public class UserService : IUserservice
{
    public string GetName()
    {
        return "IUserservice";
    }
}

public interface IOrderService
{
    string GetName();
}

public class OrderService : IOrderService
{
    public string GetName()
    {
        return "IOrderService";
    }
}

5. 場景

在 Form1 透過建構函式注入 IUserservice,並且在 Load 事件裡面呼叫 IUserservice 的取得名稱方法,點擊頁面按鈕後讓 Form2 顯示,Form2 中透過依賴注入 IOrderService 在 Load 事件裡面呼叫 IOrderService 的取得名稱方法。如果可以多次操作不報錯就是成功。

6. 開始

引用元件

<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />

增加了一個 ServiceProviderHelper 的操作類別

public static class ServiceProviderHelper
{
    /// <summary>
    /// 全域服務提供者
    /// </summary>
    public static IServiceProvider ServiceProvider { get; private set; } = null!;

    /// <summary>
    /// 初始化建構 ServiceProvider 物件
    /// </summary>
    /// <param name="serviceProvider"></param>
    /// <exception cref="ArgumentNullException"></exception>
    public static void InitServiceProvider(ServiceProvider serviceProvider)
    {
        ArgumentNullException.ThrowIfNull(serviceProvider, nameof(serviceProvider));

        ServiceProvider = serviceProvider;
    }

    /// <summary>
    /// 取得 Form 服務
    /// </summary>
    /// <param name="type"></param>
    /// <returns></returns>
    /// <exception cref="ArgumentException"></exception>
    public static Form GetFormService(Type type)
    {
        var service = ServiceProvider.GetRequiredService(type);
        if (service is Form fService)
        {
            return fService;
        }
        else
        {
            throw new ArgumentException($"{type.FullName} is not a Form");
        }
    }

    /// <summary>
    /// 取得服務
    /// </summary>
    /// <param name="type"></param>
    /// <returns></returns>
    /// <exception cref="ArgumentException"></exception>
    public static T GetService<T>() where T : class
    {
        return ServiceProvider.GetRequiredService<T>();
    }
}

修改 Program 方法

internal static class Program
{
    /// <summary>
    ///  應用程式的主要進入點。
    /// </summary>
    [STAThread]
    private static void Main()
    {
        // .NET 6 寫法(之前是三行合一行)
        ApplicationConfiguration.Initialize();

        // 建立服務容器
        var services = new ServiceCollection();
        // 加入服務註冊
        ConfigureServices(services);

        // 建構 ServiceProvider 物件
        ServiceProviderHelper.InitServiceProvider(services.BuildServiceProvider());

        // 取得指定服務
        var main = ServiceProviderHelper.ServiceProvider.GetRequiredService<Form1>();
        Application.Run(main);
    }

    /// <summary>
    /// 注入服務
    /// </summary>
    /// <param name="services"></param>
    public static void ConfigureServices(IServiceCollection services)
    {
        // 批次注入可以使用 Scrutor 或者自己封裝
        services.AddScoped<IUserservice, UserService>();
        services.AddScoped<IOrderService, OrderService>();

        // 其他的表單也可以注入在此處
        services.AddSingleton(typeof(Form1));
        services.AddTransient(typeof(Form2));
    }
}

分別在 Form1 和 Form2 進行注入

private readonly IUserservice _userservice;

public Form1(IUserservice userservice)
{
    InitializeComponent();
    _userservice = userservice;
}

private readonly IOrderService _orderService;

public Form2(IOrderService orderService) : this()
{
    _orderService = orderService;
}

點擊 Form1 表單按鈕讓 Form2 表單顯示

private void button1_Click(object sender, EventArgs e)
{
    var form2 = ServiceProviderHelper.GetFormService(typeof(Form2));
    form2.Show();
}

正常操作幾次並沒有發現異常。

7. 資料

在 .NET Core 3.1 上基於 Winform 實現依賴注入實例:http://www.ty2y.com/study/znetcore3.1sjywinformsxylzrsl.html

繼續探索

延伸閱讀

更多文章
同分類 / 同標籤 2024/2/29

Winform中也可以這樣做資料展示

在做winform開發的過程中,經常需要做資料展示的功能,之前一直使用的是gridcontrol控制項,今天想透過一個範例,跟大家介紹一下如何在winform blazor hybrid中使用ant design blazor中的table元件做資料展示。

繼續閱讀
同分類 / 同標籤 2024/2/29

Winform的介面也可以變好看?

前幾天跟大家介紹了在winform中使用blazor hybrid,而且還說配上blazor的UI可以讓我們的winform程式設計的更加好看,接下來我想以一個在winform blazor hybrid中繪圖的範例來進行說明,希望對你有所幫助。

繼續閱讀