Bunun için kolay bir uzantı noktası var gibi görünmüyor, ancak özel bir sözleşme kullanarak oldukça iyi bir çözümle çalıştım. Yaptığım kararları anlamanıza yardımcı olmak için birkaç adımdan geçeceğim (yolumda yaptığım birçok yanlış adımı atladım).
Öncelikle kullanmakta olduğunuz DefaultConvention'a bakalım.
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));
}
}
Oldukça basit, biz tipi ve arayüz çift olsun ve onlar biz onları kayıt yaparsak ta, bir kurucuya sahip emin olmak için kontrol edin. DecorateWith'i çağırması için bunu değiştirmek güzel olurdu, ancak bunu yalnızca <>() için kullanabilirsiniz. <>() kullanın, For(). Use().
Sonraki bakalım DecorateWith ne:
public T DecorateWith(Expression<Func<TPluginType, TPluginType>> handler)
{
this.AddInterceptor((IInterceptor) new FuncInterceptor<TPluginType>(handler, (string) null));
return this.thisInstance;
}
Yani bu FuncInterceptor oluşturur ve bunu kaydeder.
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());
}
}
Bu sınıf sadece daha kolay biz tip varken çalışmayı kolaylaştırır: Ben sadece yeni bir sınıf yapmak kolay olurdu karar vermeden önce bu dinamik yansıması ile birini oluşturmaya çalışan zaman adil biraz geçirdi değişken olarak
Son olarak, Varsayılan sözleşmeye dayalı olarak kendi Sözleşmemizi yaptım.
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);
}
}
Onun neredeyse tamamen aynı tek eklenmesiyle, biz kayıt her türü için bir önleme ve interceptorType oluşturun. O zaman bu politikayı kaydederim. Bazı (daha kolay yapılandırmak yapmak, daha fazla test, bu KURU yapmak, önbelleğe alma) Buraya temizlemek için kesinlikle yer var
[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
{
}
ama işe yarar:
Son olarak, bunu kanıtlamak için birkaç ünite testleri işleri ihtiyacınız olan ve bunu yapmanın oldukça mantıklı bir yolu.
Lütfen başka sorularınız mı var?
Bunu işe aldınız mı? –
Maalesef hayır. Eklenti türlerimin her biri için bunları manuel olarak ekledim. – rinat