Unity: Conditional resolving

2019-09-14 21:09发布

I'm looking to use Unity to resolve types at runtime based on specific data received. My code (similar to that shown below) currently registers the types in a bootstrapper class at start-up and then within the main flow a decision is made on what type is required.

What I'm looking to do is replace the code lines that use the 'new' keyword with a resolver, however as this code is outwith my bootstrapper I'm not sure how this can be done...I'm new to Unity so please go easy.

// In Bootstrapper class
resolver.RegisterType<IDataType1, DataType1>();
resolver.RegisterType<IDataType2, DataType2>();
resolver.RegisterType<IDataType3, DataType3>();


// Main flow...outwith bootstrapper
switch (dataRecordType)
{
    case DataRecordType.dataType1:
        DataType1 dt1 = new DataType1();
        dt1.ProcessData();
        break;

    case DataRecordType.dataType2:
        DataType2 dt2 = new DataType2();
        dt2.ProcessData();
        break;

    case DataRecordType.dataType3:
        DataType3 dt3 = new DataType3();
        dt3.ProcessData();
        break;

    default:
        break;
}

1条回答
欢心
2楼-- · 2019-09-14 21:48

You are missing a few abstractions here. You're missing an general abstraction over your data types and an abstraction for creating implementations of those data types:

// In your core layer
public interface IDataType {
    void ProcessData();
}

public interface IDataTypeFactory {
    IDataType Create(DataRecordType dataRecordType);
}

// In Bootstrapper class
resolver.RegisterInstance<IDataTypeFactory>(new DataTypeFactory(resolver));
resolver.RegisterType<IDataType1, DataType1>();
resolver.RegisterType<IDataType2, DataType2>();
resolver.RegisterType<IDataType3, DataType3>();

private sealed class DataTypeFactory : IDataTypeFactory {
    private readonly IUnityContainer container;
    public DataTypeFactory(IUnityContainer container) {
        this.container = container;
    }

    public IDataType Create(DataRecordType dataRecordType) {
        switch (dataRecordType) {
            case DataRecordType.dataType1:
                return this.container.Resolve<IDataType1>();
            case DataRecordType.dataType2:
                return this.container.Resolve<IDataType2>();
            case DataRecordType.dataType3:
                return this.container.Resolve<IDataType3>();
            default:
                throw new InvalidEnumArgumentException();
        }
    }
}

What you can see is that the code for creating implementations is moved to the factory. Now the remaining application code can be comes something like this:

// Main flow...outwith bootstrapper
IDataType dt = this.dataTypeFactory.Create(dataRecordType);
dt.ProcessData();

The IDataType1, IDataType2 and IDataType3 are now only used in the bootstrapper and have become redundant (or at least, redundant with the code you presented), so you could even remove them all together and change the bootstrap logic to the following:

// In Bootstrapper class
resolver.RegisterInstance<IDataTypeFactory>(new DataTypeFactory(resolver));
resolver.RegisterType<DataType1>();
resolver.RegisterType<DataType2>();
resolver.RegisterType<DataType3>();

private sealed class DataTypeFactory : IDataTypeFactory {
    private readonly IUnityContainer container;
    public DataTypeFactory(IUnityContainer container) {
        this.container = container;
    }

    public IDataType Create(DataRecordType dataRecordType) {
        switch (dataRecordType) {
            case DataRecordType.dataType1:
                return this.container.Resolve<DataType1>();
            case DataRecordType.dataType2:
                return this.container.Resolve<DataType2>();
            case DataRecordType.dataType3:
                return this.container.Resolve<DataType3>();
            default:
                throw new InvalidEnumArgumentException();
        }
    }
}
查看更多
登录 后发表回答