C# 依賴注入框架Grace
Grace是一個我偶爾刷技術博客的時候才知道的依賴注入框架,根據項目的github瞭解到,Grace是一個開源、輕巧、易用同時特性豐富、性能優秀的依賴注入容器框架。
Grace is a feature-rich dependency injection container designed with ease of use and performance in mind.
比較令人詫異的是,Grace的作者Ian Johnson,幾乎沒有寫任何文檔,而且用法也找不到任何中文資料,哪怕是英文的使用文檔和教程也是很少,我試圖從stack overflow上找,也是寥寥無幾的問題,最後我還是從作者的Github項目主頁的Issues中找到了使用的蛛絲馬跡,居然是從作者的單元測試中找用法Demo。簡直厲害了。
1. 項目鏈接
Nuget:https://www.nuget.org/packages/Grace/
Github:https://github.com/ipjohnson/Grace
測評鏈接 IoC Container Benchmark - Performance comparison
2. 倉儲類Demo設計
按照作者給出的Demo,稍加改造一下,Ian Johnson設計了賬戶/用戶/服務三個接口倉儲類作爲Demo的演示用例,我在這裏列出一下。
/// <summary>
/// 賬戶倉儲接口
/// </summary>
public interface IAccountRepository
{
string Get();
}
/// <summary>
/// 賬戶倉儲類
/// </summary>
public class AccountRepository : IAccountRepository
{
public string Get()
{
return "[AccountRepository] 簡單註冊調用";
}
}
/// <summary>
/// 賬戶服務接口
/// </summary>
public interface IAccountService
{
string Get();
}
/// <summary>
/// 賬戶服務類
/// </summary>
public class AccountService : IAccountService
{
IAccountRepository _accountRepository;
public AccountService(IAccountRepository accountRepository)
{
_accountRepository = accountRepository;
}
public string Get()
{
return _accountRepository.Get() + " [AccountService] ";
}
}
/// <summary>
/// 用戶倉儲接口
/// </summary>
public interface IUserRepository
{
string Get();
}
/// <summary>
/// 用戶倉儲A類
/// </summary>
public class UserRepositoryA : IUserRepository
{
public string Get()
{
return "[UserRepositoryA] 鍵值註冊調用 ";
}
}
/// <summary>
/// 用戶倉儲B類
/// </summary>
public class UserRepositoryB : IUserRepository
{
public UserRepositoryB(string param1, string param2)
{
Console.WriteLine($"Ctor param1:{param1} {param2}");
}
public string Get()
{
return "[UserRepositoryB] 鍵值註冊調用 ";
}
}
/// <summary>
/// 用戶服務接口
/// </summary>
public interface IUserService
{
string Get();
}
/// <summary>
/// 用戶服務類
/// </summary>
public class UserService : IUserService
{
IUserRepository _userRepository;
public UserService(IUserRepository userRepository)
{
_userRepository = userRepository;
}
public string Get()
{
return _userRepository.Get() + " [UserService] ";
}
}
3. 注入實例演示
Grace框架注入操作也和其他的IoC一樣,也是先聲明一個容器,再按照幾個特定的模式進行相應的注入,這裏有點不明白的是,爲何UserRepositoryB的構造參數有兩個,但是注入的時候給的參數只有一個,但實例接收到的卻依然是兩個參數,一模一樣的參數,等於複製了兩份,如果有大神看懂了其中的奧妙,幫忙告訴我一下哈,十分感謝!
//容器
var container = new DependencyInjectionContainer();
container.Configure(m =>
{
//這裏演示如何簡單註冊同一個接口對應其實現
m.Export<AccountRepository>().As<IAccountRepository>();
m.Export<AccountService>().As<IAccountService>();
//這裏演示如何使用鍵值以單例的模式註冊同一個接口的多個實現
m.Export<UserRepositoryA>().AsKeyed<IUserRepository>("A").Lifestyle.Singleton();
//這裏同時演示使用帶參數構造器來鍵值註冊
m.Export<UserRepositoryB>().AsKeyed<IUserRepository>("B").WithCtorParam<string>(
() => {
return "paramA";
}
);
//這裏演示依賴倒置而使用構造器帶鍵值注入
m.Export<UserService>().As<IUserService>().WithCtorParam<IUserRepository>().LocateWithKey("B");
});
4. 使用實例演示
使用也很簡潔明瞭,用容器對象和註冊類型定位一下就可以,關於生命週期,Grace框架裏提供了幾種,還可以自行擴展,這點比較強大。給定的幾種模式分別是 Singleton, SingletonPerScope, SingletonPerRequest , SingletonPerObjectGraph, SingletonPerAncestor, and WeakSingleton,這幾個模式的從英文意思上大概可以猜出來,但是大神 Ian Johnson 沒有給出來文檔和Demo,估計大神是想讓我們看他的源碼自己意會,也可能是大神覺得很簡單,簡單到不用直接說明。。。。
Many LifeStyles supported including Singleton, SingletonPerScope, SingletonPerRequest (MVC4, MVC5 & WCF packages), SingletonPerObjectGraph, SingletonPerAncestor, and WeakSingleton. If none of the provided life styles meet your need you can always implement your own ICompiledLifeStyle class.
//獲取簡單註冊實例
var accountRepo = container.Locate<IAccountRepository>();
Console.WriteLine(accountRepo.Get());
// [AccountRepository] 簡單註冊調用
var accountSvc = container.Locate<IAccountService>();
Console.WriteLine(accountSvc.Get());
// [AccountRepository] 簡單註冊調用 [AccountService]
Console.WriteLine();
//獲取指定鍵值的實例
var userRepo1 = container.Locate<IUserRepository>(withKey: "A");
var userRepo2 = container.Locate<IUserRepository>(withKey: "A");
// 判斷單例兩個對象是否相等
bool isEqual = userRepo1.Equals(userRepo2);
Console.WriteLine(isEqual); // True
Console.WriteLine(userRepo1.Get());
// [UserRepositoryA] 鍵值註冊調用
var userRepoB = container.Locate<IUserRepository>(withKey: "B");
Console.WriteLine(userRepoB.Get());
// Ctor param: paramA paramA
// [UserRepositoryB] 鍵值註冊調用
Console.Read();
5. 難點存疑
1、 不太清楚多個構造函數的實例怎麼注入,暫時沒找到Demo,可能得擼代碼。
2、各種生命週期的實例還沒有深入理解。