簡體   English   中英

有沒有比這更好的方法將函數注入Unity中的對象?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM