统一和对象创建

发布于 2024-09-03 05:52:27 字数 2448 浏览 4 评论 0原文

我使用 unity 作为我的 IoC 容器。我正在尝试实现一种 IProviderRepository 类型。具体实现有一个接受 IRepository 类型的构造函数。当我从具体实现中删除构造函数参数时,一切正常。我确信容器接线正确。当我尝试使用构造函数创建具体对象时,我收到以下错误:

“当前构建操作(构建密钥 Build Key[EMRGen.Infrastruct.Data.IRepository1[EMRGen.Model.Provider.Provider], null])失败:当前类型 EMRGen.Infrastruct.Data。 IRepository1[EMRGen.Model.Provider.Provider] 是一个接口,无法构造。您是否缺少类型映射(策略类型 BuildPlanStrategy,索引 3)。

Unity是否可以实现上述功能?即让 Unity 从接口推断具体类型,并根据构造函数参数向具体类型的构造函数注入适当的具体对象。下面是我在 Unity 中定义的类型的示例以及我想要实现的目标的骨架类列表。 IProviderRepository 由 ProviderRepository 实现,它有一个需要 IRepository 类型的构造函数。

 <typeAlias alias="ProviderRepositoryInterface" type="EMRGen.Model.Provider.IProviderRepository, EMRGen.Model" />
 <typeAlias alias="ProviderRepositoryConcrete" type="EMRGen.Infrastructure.Repositories.Providers.ProviderRepository, EMRGen.Infrastructure.Repositories" />
 <typeAlias alias="ProviderGenericRepositoryInterface" type="EMRGen.Infrastructure.Data.IRepository`1[[EMRGen.Model.Provider.IProvider, EMRGen.Model]], EMRGen.Infrastructure" />
 <typeAlias alias="ProviderGenericRepositoryConcrete" type="EMRGen.Infrastructure.Repositories.EntityFramework.ApplicationRepository`1[[EMRGen.Model.Provider.Provider, EMRGen.Model]], EMRGen.Infrastructure.Repositories" />
 <!-- Provider Mapping-->
 <typeAlias alias="ProviderInterface" type="EMRGen.Model.Provider.IProvider, EMRGen.Model" />
 <typeAlias alias="ProviderConcrete" type="EMRGen.Model.Provider.Doctor, EMRGen.Model" />

说明在我的班级中进行的调用:

public class PrescriptionService
{
     PrescriptionService()
     {
         IUnityContainer uc = UnitySingleton.Instance.Container;
         UnityServiceLocator unityServiceLocator = new UnityServiceLocator(uc);
         ServiceLocator.SetLocatorProvider(() => unityServiceLocator);
         IProviderRepository pRepository =
             ServiceLocator.Current.GetInstance<IProviderRepository>();
     }
}

public class GenericRepository<IProvider> : IRepository<IProvider>
{
}

public class ProviderRepository :  IProviderRepository
{
    private IRepository<IProvider> _genericProviderRepository;

    //Explict public default constructor
    public ProviderRepository(IRepository<IProvider> genericProviderRepository) 
    {
        _genericProviderRepository = genericProviderRepository;
    }
}

I am using unity as my IoC container. I am trying to implement a type of IProviderRepository. The concrete implementation has a constructor that accepts a type of IRepository. When I remove the constructor parameter from the concrete implementation everything works fine. I am sure the container is wired correctly. When I try to create the concrete object with the constructor I receive the following error:

"The current build operation (build key Build Key[EMRGen.Infrastructure.Data.IRepository1[EMRGen.Model.Provider.Provider], null]) failed: The current type, EMRGen.Infrastructure.Data.IRepository1[EMRGen.Model.Provider.Provider], is an interface and cannot be constructed. Are you missing a type mapping? (Strategy type BuildPlanStrategy, index 3)".

Is it possible to achieve the above mention functionality with Unity? Namely have Unity infer a concrete type from the Interface and also inject the constructor of the concrete type with the appropriate concrete object based on constructor parameters. Below is sample of my types defined in Unity and a skeleton class listing for what I want to achieve. IProviderRepository is implemented by ProviderRepository which has a constructor that expects a type of IRepository.

 <typeAlias alias="ProviderRepositoryInterface" type="EMRGen.Model.Provider.IProviderRepository, EMRGen.Model" />
 <typeAlias alias="ProviderRepositoryConcrete" type="EMRGen.Infrastructure.Repositories.Providers.ProviderRepository, EMRGen.Infrastructure.Repositories" />
 <typeAlias alias="ProviderGenericRepositoryInterface" type="EMRGen.Infrastructure.Data.IRepository`1[[EMRGen.Model.Provider.IProvider, EMRGen.Model]], EMRGen.Infrastructure" />
 <typeAlias alias="ProviderGenericRepositoryConcrete" type="EMRGen.Infrastructure.Repositories.EntityFramework.ApplicationRepository`1[[EMRGen.Model.Provider.Provider, EMRGen.Model]], EMRGen.Infrastructure.Repositories" />
 <!-- Provider Mapping-->
 <typeAlias alias="ProviderInterface" type="EMRGen.Model.Provider.IProvider, EMRGen.Model" />
 <typeAlias alias="ProviderConcrete" type="EMRGen.Model.Provider.Doctor, EMRGen.Model" />

Illustrate the call being made inside my class:

public class PrescriptionService
{
     PrescriptionService()
     {
         IUnityContainer uc = UnitySingleton.Instance.Container;
         UnityServiceLocator unityServiceLocator = new UnityServiceLocator(uc);
         ServiceLocator.SetLocatorProvider(() => unityServiceLocator);
         IProviderRepository pRepository =
             ServiceLocator.Current.GetInstance<IProviderRepository>();
     }
}

public class GenericRepository<IProvider> : IRepository<IProvider>
{
}

public class ProviderRepository :  IProviderRepository
{
    private IRepository<IProvider> _genericProviderRepository;

    //Explict public default constructor
    public ProviderRepository(IRepository<IProvider> genericProviderRepository) 
    {
        _genericProviderRepository = genericProviderRepository;
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

×眷恋的温暖 2024-09-10 05:52:27

您想要做的事情是可能的,但是您需要告诉 Unity 如何从接口映射到具体类型。 AFAICT,您当前的配置注册了很多类型,但没有指定它们如何相互关联。

也就是说,静态服务定位器是一种反模式。考虑更改您的代码以使用正确的构造函数注入。这也将大大简化您的代码:

public class PrescriptionService
{
    private readonly IProviderRepository pRepository;

    public PrescriptionService(IProviderRepository pRepository)
    {
        if (pRepository == null)
        {
            throw new ArgumentNullException("pRepository");
        }

        this.pRepository = pRepository;
    }
}

使用 Unity,您可以像这样连接它:

var container = new UnityContainer();
container.RegisterType<PrescriptionService>();
container.RegisterType<IProviderRepository, ProviderRepository>();
container.RegisterType<IRepository<IProvider>, MyRepository<IProvider>>();

var ps = container.Resolve<PrescriptionService>();

配置容器和 解析应用程序组合根中的所有组件

您应该仅在需要时才使用 XML 配置无需重新编译应用程序即可更改某些组件

What you want to do is possible, but you need to tell Unity how to map from interfaces to concrete types. AFAICT, your current configuration registers a lot of types, but doesn't specify how they relate to each other.

That said, static Service Locator is an anti-pattern. Consider changing your code to use proper Constructor Injection instead. That would also simplify your code considerably:

public class PrescriptionService
{
    private readonly IProviderRepository pRepository;

    public PrescriptionService(IProviderRepository pRepository)
    {
        if (pRepository == null)
        {
            throw new ArgumentNullException("pRepository");
        }

        this.pRepository = pRepository;
    }
}

Using Unity, you would be able to wire it up like this:

var container = new UnityContainer();
container.RegisterType<PrescriptionService>();
container.RegisterType<IProviderRepository, ProviderRepository>();
container.RegisterType<IRepository<IProvider>, MyRepository<IProvider>>();

var ps = container.Resolve<PrescriptionService>();

Configure the container and resolve all components in the application's Composition Root.

You should only use XML configuration if you need to be able to change certain components without recompiling your application.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文