看起来需要实现一个自定义的IInterceptorPolicy。它将被调用以处理容器中所有类型,并可以为其中的一些或全部类型产生装饰器。
以下是一个使用虚拟记录器输出到控制台的示例:
public class CustomInterception : IInterceptorPolicy
{
public string Description => "test interception Console.WriteLine each method' arguments and return value";
public IEnumerable<IInterceptor> DetermineInterceptors(Type pluginType, StructureMap.Pipeline.Instance instance)
{
Type dispatchProxyType = DummyDispatchProxyDontUseAtWork.GenerateStructureMapCompatibleDispatchProxyType(pluginType);
yield return new DecoratorInterceptor(pluginType, dispatchProxyType);
}
}
称为:
var container = new StructureMap.Container(cntnr =>
);
var foo = container.GetInstance<IFoo>();
foo.FooFoo("1", "2");
生成的输出:
FooFoo(1,2)
BarBar(2,1)
BarBar -> 21
FooFoo -> 21
下面是示例的其余部分,因此可以执行。
使用
DispatchProxy
的棘手之处在于它创建了一个新类型,很难由
StructureMap
构造。 在
.Net Core 2.1
中,
DispatchProxy
使用
Action...
参数创建构造函数,但
StructureMap
需要可创建的内容。 您绝对需要另一种代理生成器才能更顺畅地与
StructureMap
配合使用。
public interface IBar
{
string BarBar(string a1, string a2);
}
public class Bar : IBar
{
public string BarBar(string a1, string a2) => a1 + a2;
}
public interface IFoo
{
string FooFoo(string a1, string a2);
}
public class Foo : IFoo
{
public IBar Bar { get; private set; }
public Foo(IBar bar)
{
Bar = bar;
}
public string FooFoo(string a1, string a2) => Bar.BarBar(a2, a1);
}
public class DummyDispatchProxyDontUseAtWork : DispatchProxy
{
public object Instance { get; protected set; }
public DummyDispatchProxyDontUseAtWork() : base()
{}
protected override object Invoke(MethodInfo targetMethod, object[] args)
{
Console.WriteLine($"{targetMethod.Name}({string.Join(',', args)})");
var result = targetMethod.Invoke(this.Instance, args);
Console.WriteLine($" {targetMethod.Name} -> {result}");
return result;
}
private static readonly ConcurrentDictionary<Type, Type> generatedProxyTypes = new ConcurrentDictionary<Type, Type>();
protected static readonly ConcurrentDictionary<string, object> privateHackedState = new ConcurrentDictionary<string, object>();
private static readonly AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(Guid.NewGuid().ToString()), AssemblyBuilderAccess.Run);
private static readonly ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(Guid.NewGuid().ToString());
private static Type EmitDispatchProxyType(Type interfaceType)
{
object dispatchProxyObj = typeof(DispatchProxy).GetMethod("Create", BindingFlags.Static | BindingFlags.Public)
.MakeGenericMethod(interfaceType, typeof(DummyDispatchProxyDontUseAtWork))
.Invoke(null, null);
string typeId = "DummyDispatchProxyDontUseAtWork" + Guid.NewGuid().ToString("N");
privateHackedState[typeId] =
dispatchProxyObj.GetType().GetField("invoke", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(dispatchProxyObj);
var resultTypeBuilder = moduleBuilder.DefineType(
typeId,
TypeAttributes.Public,
dispatchProxyObj.GetType());
var baseCtor = dispatchProxyObj.GetType().GetConstructors().First();
var ctor = resultTypeBuilder.DefineConstructor(
MethodAttributes.Public,
CallingConventions.Standard,
new[] {interfaceType});
var il = ctor.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldsfld, typeof(DummyDispatchProxyDontUseAtWork).GetField(nameof(privateHackedState), BindingFlags.NonPublic | BindingFlags.Static));
il.Emit(OpCodes.Ldstr, typeId);
il.Emit(OpCodes.Callvirt, typeof(ConcurrentDictionary<,>).MakeGenericType(typeof(string), typeof(object)).GetMethod("get_Item"));
il.Emit(OpCodes.Call, baseCtor);
var setInstanceMethodInfo = dispatchProxyObj.GetType()
.GetMethod("set_" + nameof(Instance),BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Call, setInstanceMethodInfo);
il.Emit(OpCodes.Ret);
return resultTypeBuilder.CreateType();
}
public static Type GenerateStructureMapCompatibleDispatchProxyType(Type interfaceType)
{
return generatedProxyTypes.GetOrAdd(interfaceType, EmitDispatchProxyType);
}
}