2015-10-26 2 views
0

Я хочу реализовать decorator pattern с помощью StructureMap 4.
Я создал интерфейс IDeveloper и две реализаций
CSharpDeveloper, который декорированный типа и DeveloperDecorator
который является декоратором.
Тип декоратора имеет зависимость от IDeveloper, а сам класс реализует IDevloper, что означает, что один из типов должен быть именованным экземпляром.
Названного экземпляр CSharpDeveloperStructureMap 4 Конструктора зависимости с именем экземпляром

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>() апи.
У меня есть тип под названием 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); 
      }); 
     } 
    }); 
} 

Спасибо.

ответ

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(); 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^