在运行时解析构造函数依赖(没有属性)

时间:2014-07-29 23:30:46

标签: c# unity-container

我使用Unity进行依赖注入,我希望在运行时控制,解析哪个特定类型并作为依赖项传递给构造函数。

我有一个界面:

public interface IDatabase
{
    void DoSomething();
}

这是由两个类实现的:

public class SQLDatabase : IDatabase
{
    public void DoSomething()
    {
        //Do Something on a SQL server database...
    }
}
public class OracleDatabase : IDatabase
{
    public void DoSomething()
    {
        //Do Something on an Oracle database...
    }
}

第三类依赖于IDatabase

public class DataService: IDataService
{
    public DataService(IDatabase database)
    {
        database.DoSomething();
    }
}

模块使用Unity注册每个类,并为两个IDatabase类型指定特定名称,以便区分它们:

container.RegisterType<IDatabase, SQLDatabase>("SQLDatabase");
container.RegisterType<IDatabase, OracleDatabase>("OracleDatabase");
container.RegisterType<IDataService, DataService>();

我需要创建一个Consumer的实例,此时我想指定Unity使用/注入实现IDatabase的两种类型中的哪一种,但我不知道如何告诉Unity特定类型构建/解决?我想我想要这样的东西(伪代码):

public class Consumer
{
    IDataService dataService = null;
    public Consumer(string runtimeChoice)
    {
        if (runtimeChoice == "SQLSERVER")
        {
            dataService = _container.Resolve<IDataService>("SQLDatabase");
        }
        else if (runtimeChoice == "Oracle")
        {
            dataService = _container.Resolve<IDataService>("OracleDatabase");
        }
    }
}

那么,我如何告诉Unity使用特定的命名类型解析IDatabase类型,并将其传递给依赖对象的构造函数,但是在运行时执行它?

3 个答案:

答案 0 :(得分:3)

我会改变两件事,我会尽量确保尽可能接近源代码处理这些魔术字符串,并尝试确保我的代码与容器无关。

我会有以下界面:

public interface IDataServiceFactory
{
    IDataService CreateSqlDataService();
    IDataService CreateOracleDataService();
}

使用类似的实现:

public class DataServiceFactory : IDataServiceFactory
{
    private readonly Func<IDataService> _sqlDataServiceFactory;
    private readonly Func<IDataService> _oracleDataServiceFactory;

    public DataServiceFactory(Func<IDataService> sqlDataServiceFactory, Func<IDataService> oracleDataServiceFactory)
    {
        _sqlDataServiceFactory = sqlDataServiceFactory;
        _oracleDataServiceFactory = oracleDataServiceFactory;
    }

    public IDataService CreateSqlDataService()
    {
        return _sqlDataServiceFactory();
    }


    public IDataService CreateOracleDataService()
    {
        return _oracleDataServiceFactory();
    }
}

然后我会在您的IUnityContainer注册此内容:

_container.RegisterType<IDataService, DataService>("SQLDataService", 
    new InjectionConstructor(new ResolvedParameter<IDatabase>("SQLDatabase")));

_container.RegisterType<IDataService, DataService>("OracleDataService", 
    new InjectionConstructor(new ResolvedParameter<IDatabase>("OracleDatabase")));

_container.RegisterType<IDataServiceFactory, DataServiceFactory>(new InjectionConstructor(
    new ResolvedParameter<Func<IDataService>>("SQLDataService"), 
    new ResolvedParameter<Func<IDataService>>("OracleDataService"));

现在,无论以前创建Consumer个实例,都应该依赖IDataServiceFactory并且应该处理运行时值以调用正确的方法CreateSqlDataService()CreateOracleDataService()。< / p>

现在所有的运行时代码都与容器无关,并且魔术字符串在其源旁边处理。

答案 1 :(得分:2)

我能够使用DependencyOverride解析正确的类型,它本身从unity容器中获取所需的类型。所以消费者变成了:

public class Consumer
{
    IDataService dataService = null;
    public Consumer(string runtimeChoice)
    {
        DependencyOverride<IDatabase> dependency = null;

        if (runtimeChoice == "SQLSERVER")
        {
            dependency = new DependencyOverride<IDatabase>
                                 (Container.Resolve<IDatabase>("SQLDatabase"));

        }
        else if (runtimeChoice == "Oracle")
        {
            dependency = new DependencyOverride<IDatabase>
                                 (Container.Resolve<IDatabase>("OracleDatabase"));
        }            

        dataService = _container.Resolve<IDataService>(dependency);
    }
}

答案 2 :(得分:0)

我有一个类似的要求,我需要在运行时解析'widgetbuilder'类型。在我的Unity配置中,我注册了两种类型的小部件构建器: -

.some()

然后我在运行时通过以下方法解决它们: -

        container.RegisterType<IWidgetBuilder, SinglePointWidgetBuilder>("SinglePointWidgetBuilder");
        container.RegisterType<IWidgetBuilder, CurrentVsTargetWidgetBuilder>("CurrentVsTargetWidgetBuilder");