쉽게 확장 할 수있는 것처럼 보이지 않지만 사용자 지정 규칙을 사용하여 상당히 괜찮은 솔루션을 사용하고 있습니다. 내가 한 결정을 이해하는 데 도움이되도록 몇 단계 (건너 뛴 많은 실수를 건너 뛰기)를 진행합니다.
먼저 이미 사용중인 DefaultConvention를 살펴보십시오.
DefaultConvention :
public class DefaultConventionScanner : ConfigurableRegistrationConvention
{
public override void Process(Type type, Registry registry)
{
if (!TypeExtensions.IsConcrete(type))
return;
Type pluginType = this.FindPluginType(type);
if (pluginType == null || !TypeExtensions.HasConstructors(type))
return;
registry.AddType(pluginType, type);
this.ConfigureFamily(registry.For(pluginType, (ILifecycle)null));
}
public virtual Type FindPluginType(Type concreteType)
{
string interfaceName = "I" + concreteType.Name;
return Enumerable.FirstOrDefault<Type>((IEnumerable<Type>)concreteType.GetInterfaces(), (Func<Type, bool>)(t => t.Name == interfaceName));
}
}
매우 간단, 우리는 유형과 인터페이스 쌍을 얻을 그들은 우리가 그들을 등록 할 경우 그들이 생성자를 가지고 있는지 확인하십시오. DecorateWith를 호출하도록이 코드를 수정하는 것이 좋지만 For <>()에 대해서만 호출 할 수 있습니다. For()가 아닌 <>()을 사용하십시오.
다음에서 볼 수 있습니다 DecorateWith가하는 일 :
public T DecorateWith(Expression<Func<TPluginType, TPluginType>> handler)
{
this.AddInterceptor((IInterceptor) new FuncInterceptor<TPluginType>(handler, (string) null));
return this.thisInstance;
}
그래서 이것은 FuncInterceptor를 생성하고 등록합니다.
이
public class ProxyFuncInterceptor<T> : FuncInterceptor<T> where T : class
{
public ProxyFuncInterceptor() : base(x => MakeProxy(x), "")
{
}
protected ProxyFuncInterceptor(Expression<Func<T, T>> expression, string description = null)
: base(expression, description)
{
}
protected ProxyFuncInterceptor(Expression<Func<IContext, T, T>> expression, string description = null)
: base(expression, description)
{
}
private static T MakeProxy(T instance)
{
var proxyGenerator = new ProxyGenerator();
return proxyGenerator.CreateInterfaceProxyWithTarget(instance, new LogInterceptor());
}
}
이 클래스는 그냥 쉽게 우리가 유형이있을 때 작업을 할 수 있습니다 : 난 그냥 새로운 클래스를 만들기 위해 쉽게 될 것입니다 결정하기 전에 이러한 동적 반사 중 하나를 만들려고 시간의 공정한 조금을 보냈다 변수로.
마침내 기본 규칙에 따라 본인 만의 대회를 만들었습니다.
public class DefaultConventionWithProxyScanner : ConfigurableRegistrationConvention
{
public override void Process(Type type, Registry registry)
{
if (!type.IsConcrete())
return;
var pluginType = this.FindPluginType(type);
if (pluginType == null || !type.HasConstructors())
return;
registry.AddType(pluginType, type);
var policy = CreatePolicy(pluginType);
registry.Policies.Interceptors(policy);
ConfigureFamily(registry.For(pluginType));
}
public virtual Type FindPluginType(Type concreteType)
{
var interfaceName = "I" + concreteType.Name;
return concreteType.GetInterfaces().FirstOrDefault(t => t.Name == interfaceName);
}
public IInterceptorPolicy CreatePolicy(Type pluginType)
{
var genericPolicyType = typeof(InterceptorPolicy<>);
var policyType = genericPolicyType.MakeGenericType(pluginType);
return (IInterceptorPolicy)Activator.CreateInstance(policyType, new object[]{CreateInterceptor(pluginType), null});
}
public IInterceptor CreateInterceptor(Type pluginType)
{
var genericInterceptorType = typeof(ProxyFuncInterceptor<>);
var specificInterceptor = genericInterceptorType.MakeGenericType(pluginType);
return (IInterceptor)Activator.CreateInstance(specificInterceptor);
}
}
거의 동일한 하나의 추가로, 나는 우리가 등록하는 각 유형에 대한 인터셉터와 인터셉터 유형을 만듭니다. 나는 그 정책을 등록한다. 일부는 (쉽게 구성 할 수 있도록, 더 많은 테스트, 그것은 건조하게, 캐싱) 여기에 정리를 위해 확실히 방에있다
[TestFixture]
public class Try4
{
[Test]
public void Can_create_interceptor()
{
var type = typeof (IServiceA);
Assert.NotNull(new DefaultConventionWithProxyScanner().CreateInterceptor(type));
}
[Test]
public void Can_create_policy()
{
var type = typeof (IServiceA);
Assert.NotNull(new DefaultConventionWithProxyScanner().CreatePolicy(type));
}
[Test]
public void Can_register_normally()
{
var container = new Container();
container.Configure(x => x.Scan(y =>
{
y.TheCallingAssembly();
y.WithDefaultConventions();
}));
var serviceA = container.GetInstance<IServiceA>();
Assert.IsFalse(ProxyUtil.IsProxy(serviceA));
Console.WriteLine(serviceA.GetType());
}
[Test]
public void Can_register_proxy_for_all()
{
var container = new Container();
container.Configure(x => x.Scan(y =>
{
y.TheCallingAssembly();
y.Convention<DefaultConventionWithProxyScanner>();
}));
var serviceA = container.GetInstance<IServiceA>();
Assert.IsTrue(ProxyUtil.IsProxy(serviceA));
Console.WriteLine(serviceA.GetType());
}
[Test]
public void Make_sure_I_wait()
{
var container = new Container();
container.Configure(x => x.Scan(y =>
{
y.TheCallingAssembly();
y.Convention<DefaultConventionWithProxyScanner>();
}));
var serviceA = container.GetInstance<IServiceA>();
serviceA.Wait();
}
}
}
public interface IServiceA
{
void Wait();
}
public class ServiceA : IServiceA
{
public void Wait()
{
Thread.Sleep(1000);
}
}
public interface IServiceB
{
}
public class ServiceB : IServiceB
{
}
하지만 작동 :
마지막으로, 그것을 증명하기 위해 몇 가지 단위 테스트 작동 당신이 필요로하는 것은 그것을하는 매우 합리적인 방법입니다.
다른 질문이 있으시면 문의하십시오.
작동 시키셨습니까? –
불행히도 없습니다. 각 플러그인 유형마다 수동으로 추가했습니다. – rinat