[英]Is there a better way than this to inject a function into an object in Unity?
我是一個Unity noob,我有一個問題。 我想在每個IPerson實例中注入一個IAgeCalculator,以便IAgeCalculator實例可供我以后創建的任何IPerson使用。
這是我到目前為止所嘗試的。 它有效,但感覺不對。
static void Main(string[] args)
{
IUnityContainer container = new UnityContainer();
container.RegisterType<IAgeCalculator, AgeInYearsCalculator>("Years");
container.RegisterType<IAgeCalculator, AgeInDaysCalculator>("Days");
// Using the initializer like this does not feel right,
// but I cant think of another way...
var ageCalculator = container.Resolve<IAgeCalculator>("Days");
var personInitializer = new InjectionMethod("Initializer", ageCalculator);
container.RegisterType<IPerson, Person>(personInitializer);
var person1 = Factory<IPerson>.Create(container);
person1.Name = "Jacob";
person1.Gender = "Male";
person1.Birthday = new DateTime(1995, 4, 1);
var person2 = Factory<IPerson>.Create(container);
person2.Name = "Emily";
person2.Gender = "Female";
person2.Birthday = new DateTime(1998, 10, 31);
}
這是我的類定義:
public interface IAgeCalculator
{
string GetAge(IPerson person);
}
internal class AgeInYearsCalculator : IAgeCalculator
{
public string GetAge(IPerson person) {
var years = DateTime.Now.Subtract(person.Birthday).TotalDays / 365;
return years.ToString("0.00") + " years";
}
}
internal class AgeInDaysCalculator : IAgeCalculator
{
public string GetAge(IPerson person) {
var days = (DateTime.Now.Date - person.Birthday).TotalDays;
return days.ToString("#,#") + " days";
}
}
public interface IPerson
{
string Name { get; set; }
string Gender { get; set; }
DateTime Birthday { get; set; }
string Age { get; }
}
public class Person : IPerson
{
private IAgeCalculator _ageCalculator;
public void Initializer(IAgeCalculator ageCalculator) {
_ageCalculator = ageCalculator;
}
public string Name { get; set; }
public string Gender { get; set; }
public DateTime Birthday { get; set; }
public string Age => _ageCalculator.GetAge(this);
}
public class Factory<T>
{
public static T Create(IUnityContainer container) {
return container.Resolve<T>();
}
}
有沒有更好的辦法?
DI容器的目的是構建應用程序組件的對象圖。 應用程序組件通常是包含應用程序行為的長壽命對象。 組件通常是不可變的,它們實現的服務抽象應始終是不可變的。
DI容器並不意味着構建短期和可變對象,如DTO和實體(如您的Person
對象)。 解析或注入可變的,短期的數據對象會導致歧義。 例如,如果我們注入一個Person
,我們期望得到哪個人?
這通常意味着您不應對數據對象使用構造函數注入 。 在你的情況下,甚至不需要IAgeCalculator
作為Person
對象的依賴。 Person
的消費者很容易依賴IAgeCalculator
並為正確的人調用IAgeCalculator.GetAge
。
如果您想在您的實體中放置特定於域的邏輯,則Method Injection非常適合。 這意味着負責調用該域方法的組件負責轉發所需的服務。 例如:
public void Handle(AddItemToBasketCommand command)
{
var product = this.productRepository.Get(command.ProductId);
var person = this.personRepository.Get(this.userContext.UserId);
if (product.IsAdultProduct && person.GetAge(this.ageCalculator) < 18) {
throw new ValidationException("You must be 18 to order this item.");
}
var basket = this.basketService.GetUserBasket();
basket.AddItemToBasket(command.ProductId, command.Quantity);
}
請注意,我的Person.GetAge
方法返回年齡。 在您的情況下,您的AgeCalculator
返回該人年齡的字符串表示。 這不屬於實體本身的責任。 這是一個介紹責任; 它會因為不同的原因而改變,而不是為什么其他Person類會改變。 這是在實體內部沒有這種邏輯的另一個原因。
還要注意,對你的實體進行像IPerson
這樣的抽象通常沒有多大意義。 實體是數據容器,而接口則用於抽象行為。 在Person
中沒有你想要抽象的行為,因為你不太可能希望將來有多個Person
實現。
使用RegisterInstance<T>
(不是RegisterType<T>
)注冊IAgeCalculator
並傳入從該類型派生的實例。
static void Main(string[] args)
{
IUnityContainer container = new UnityContainer();
container.RegisterInstance<IAgeCalculator>("Years", new AgeInYearsCalculator());
container.RegisterInstance<IAgeCalculator>("Days", new AgeInDaysCalculator());
container.RegisterType<IPerson, Person>();
var person1 = Factory<IPerson>.Create(container);
person1.Name = "Jacob";
person1.Gender = "Male";
person1.Birthday = new DateTime(1995, 4, 1);
var person2 = Factory<IPerson>.Create(container);
person2.Name = "Emily";
person2.Gender = "Female";
person2.Birthday = new DateTime(1998, 10, 31);
}
然后在Person
類中,使用[Dependency]
屬性標記AgeCalculator
。
public class Person : IPerson
{
[Dependency("Days")]
public IAgeCalculator AgeCalculator { get; set; }
public string Name { get; set; }
public string Gender { get; set; }
public DateTime Birthday { get; set; }
public string Age => AgeCalculator.GetAge(this);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.