StructureMap 4与命名实例的构造函数依赖关系

时间:2015-10-26 21:51:00

标签: c# ioc-container structuremap constructor-injection

我想使用StructureMap 4实现decorator pattern 我创建了一个界面IDeveloper和两个实现 CSharpDeveloper是装饰类型,DeveloperDecorator
这是装饰者。
装饰器类型依赖于IDeveloper,类本身实现IDevloper,这意味着其中一个类型应该是命名实例。
命名实例是CSharpDeveloper

public interface IDeveloper
{
}

public class CSharpDeveloper : IDeveloper
{
}

public class DeveloperDecorator : IDeveloper
{
    private readonly IDeveloper developer = null;

    public DeveloperDecorator(IDeveloper developer) {
        this.developer = developer;
    }
}

我想将DeveloperDecorator注册为IDeveloper,我可以使用未命名的GetInstance重载函数来解析类型

container.GetInstance<IDeveloper>();

和StructureMap将能够将依赖类型解析为命名实例。像这样的东西(概念代码)

Func<IDeveloper> factory = () => {
    return new DeveloperDecorator(container.GetInstance<IDeveloper>("name"));
};               

我根本不能使用泛型,所以我无法使用Ctor<TCtorType>() api。
我有一个名为TypeMap的类型,它包含服务类型,具体类型和可选名称。

public class TypeMap
{
    public string Name { get; set; }
    public Type ServiceType { get; set; }
    public Type ConcreteType { get; set; }
}

我尝试使用依赖关系,但没有任何效果。

public void Register(TypeMap typeMap, ITypeMapCollection dependencies = null) {
    container.Configure(x => {
        var use = x.For(typeMap.ServiceType)
                   .Add(typeMap.ConcreteType);

        if (typeMap.Name.IsNotNullOrEmpty()) {
            use.Named(typeMap.Name);
        }

        if (dependencies.IsNotNullOrEmpty()) {
            dependencies.ForEach(dependency => {
                use.Dependencies.Add(dependency.Name, dependency.ServiceType);
            });
        }
    });
}

感谢。

1 个答案:

答案 0 :(得分:0)

我设法通过向Use方法提供一个表达式树来创建实例并通过容器解析所有依赖项。

public void Register(TypeMap typeMap, ITypeMapCollection dependencies = null) {
    container.Configure(x => {
        var use = x.For(typeMap.ServiceType)
                   .Use(typeMap.ConcreteType);

        if (typeMap.Name.IsNotNullOrEmpty()) {
            use.Named(typeMap.Name);
        }

        if (dependencies.IsNotNullOrEmpty()) {
            x.For(typeMap.ServiceType).Use("composite", BuildExpression(typeMap, dependencies));
        }
    });
}

private Func<IContext, object> BuildExpression(TypeMap typeMap, ITypeMapCollection dependencies) {
    var contextParameter = Expression.Parameter(typeof(IContext), "context");
    var @params = dependencies.ToArray(d => d.ServiceType);
    var ctorInfo = typeMap.ConcreteType.GetConstructor(@params);
    var genericMethodInfo = typeof(IContext).GetMethods().First(method => {
        return method.Name.Equals("GetInstance") &&
                method.IsGenericMethodDefinition &&
                method.GetParameters().Length == 1;
    });

    var getInstanceCallExpressions = dependencies.Select(dependency => {
        var nameParam = Expression.Constant(dependency.Name, typeof(string));
        var methodInfo = genericMethodInfo.MakeGenericMethod(new[] { dependency.ServiceType });

        return Expression.Call(contextParameter, methodInfo, new[] { nameParam });
    });

    var lambda = Expression.Lambda<Func<IContext, object>>(
                    Expression.New(ctorInfo, getInstanceCallExpressions),
                    contextParameter);

    return lambda.Compile();
}