Dot-Net

當類型 T 的祖先時 Ninject 綁定

  • April 2, 2013

我有一個大致如下所示的依賴鏈:

public class CarSalesBatchJob
{
   public CarSalesBatchJob(IFileProvider fileProvider)
   { ... }
}

public class MotorcycleSalesBatchJob
{
   public MotorcycleSalesBatchJob(IFileProvider fileProvider)
   { ... }
}    

public class FtpFileProvider : IFileProvider
{
   public FtpFileProvider(IFtpSettings settings)
   { ... }
}

public class CarSalesFtpSettings : IFtpSettings { ... }
public class MotorcycleSalesFtpSettings : IFtpSettings { ... }

到目前為止,我一直在使用基於約定的綁定,但這還不夠好,因為我已經為IFtpSettings. 所以我決定使用一些上下文綁定。乍一看kernel.Bind<>().To<>().WhenInjectedInto<>()看起來很有希望,但這僅在第一級有幫助,這意味著如果我有 aCarSalesFtpFileProvider和 aMotorcycleSalesFtpProvider我可以這樣做:

kernel.Bind<IFtpSettings>().To<CarSalesFtpSettings>()
   .WhenInjectedInto<CarSalesFtpFileProvider>();
kernel.Bind<IFtpSettings>().To<MotorcycleSalesFtpSettings>()
   .WhenInjectedInto<MotorcycleSalesFtpFileProvider>();

但是創建兩個具體的實現似乎很愚蠢FtpFileProvider,實際上只是在我希望它們使用的設置上有所不同。我看到有一個方法叫做WhenAnyAnchestorNamed(string name). 但是這條路線需要我在批處理作業中添加屬性和魔術字元串,我對此並不感到興奮。

我還注意到.When(Func<IRequest, bool>)綁定語句有一個簡單的舊方法,所以我想出了這個作為我的綁定語句:

//at this point I've already ran the conventions based bindings code so I need to unbind
kernel.Unbind<IFtpSettings>();
kernel.Bind<IFtpSettings>().To<CarSalesFtpSettings>()
   .When(r => HasAncestorOfType<CarSalesBatchJob>(r));
kernel.Bind<IFtpSettings>().To<MotorcycleSalesFtpSettings>()
   .When(r => HasAncestorOfType<MotorcycleSalesBatchJob>(r));

// later on in the same class
private static bool HasAncestorOfType<T>(IRequest request)
{
   if (request == null)
       return false;

   if (request.Service == typeof(T))
       return true;

   return HasAncestorOfType<T>(request.ParentRequest);
}

因此,如果建構子請求 IFtpSettings,我們會遞歸請求樹以查看鏈中是否有任何請求的服務/類型與提供的類型(CarSalesBatchJob 或 MotorcycleSalesBatchJob)匹配,如果匹配則返回 true。如果我們一直到達鏈的頂部,則返回 false。

抱歉,背景解釋太長了。

**這是我的問題:我有什麼理由不應該以這種方式解決問題?**這被認為是不好的形式嗎?有沒有更好的方法來查找祖先請求類型?我應該將我的類/依賴鏈重組為更“令人愉快”的方式嗎?

您應該使用request.Target.Member.ReflectedType而不是request.ServiceThis 是實現類型。

此外,WhenAnyAncestorNamed 不需要屬性。您可以使用該Named方法標記您的作業的綁定。

這並不是您問題的真正答案,但您可以通過編寫一個類來解決您的問題,如下所示:

private sealed class FtpFileProvider<TFileProvider>
    : FtpFileProvider
   where TFileProvider : IFileProvider
{
   public FtpFileProvider(TFileProvider settings)
       : base(settings) { }
}

在這種情況下,您的配置將如下所示:

kernel.Bind<IFileProvider>()
   .To<FtpFileProvider<CarSalesFtpSettings>>()
   .WhenInjectedInto<CarSalesBatchJob>();

kernel.Bind<IFileProvider>()
   .To<FtpFileProvider<MotorcycleSalesFtpSettings>>()
   .WhenInjectedInto<MotorcycleSalesBatchJob>();

請注意,根據我的經驗,我發現在大多數情況下,您認為需要基於上下文的注入,但實際上您的設計存在缺陷。但是,根據給定的資訊,在您的情況下,我不可能對此發表任何看法,但您可能想看看您的程式碼。您可能能夠以實際上不需要基於上下文的注入的方式重構您的程式碼。

引用自:https://stackoverflow.com/questions/10921890