gpt4 book ai didi

c# - 我如何为公共(public)接口(interface)类型编写我自己的装饰器实用程序(动态代理如何工作)?

转载 作者:行者123 更新时间:2023-11-30 12:51:33 25 4
gpt4 key购买 nike

我注意到,有时对于具有非常简单的基本情况(不是批评)的事物,存在完整的框架作品。例如,您可以使用几行代码和哈希表制作服务定位器,或者您可以使用整个框架。

也就是说,我很好奇是否有一种同样简单的自己动手做装饰器的方法。 (如果我不正确地使用了这个模式的名称,请纠正我,我是这个词的新手)。

动机:我很好奇像 CaSTLe Dynamic Proxy 这样的东西是如何工作的......

如何编写 MyContainer.Get(Action before,Action after)?

public interface IFoo { 
void F();
}
public class Foo : IFoo {
public void F() {
Console.WriteLine("foo");
}
}
IFoo foo = MyContainer.Get<IFoo>(
() => { Console.WriteLine("before foo"); },
() => { Console.WriteLine("after foo"); });
foo.F();

输出将是:

before foo
foo
after foo

最佳答案

据我了解,至少有两种生成运行时代码的方法 - 如果您习惯使用 IL,则可以使用 Reflection.Emit , 否则你可以使用 CSharpCodeProvider这使您能够在运行时从字符串或一系列以 DOM 样式描述代码的对象编译代码。

这实际上是我第一次使用 CSharpCodeProvider,但这是我尝试使用它在运行时为接口(interface)创建代理类。这不是一个完整的解决方案,但如果有以下条件,它应该是一个不错的开始:

  1. 它不包括将 Lambdas 转换为字符串。据我了解,this can be done .

  2. 每次调用都创建一个新的编译器不会很好地执行;您可以在每个接口(interface)类型的基础上缓存编译器。

  3. 编译源代码后,您可以(并且应该)检查 results 对象以确保编译成功:

代码如下:

public static T Get<T>(Action beforeMethodCall, Action afterMethodCall)
{
Type interfaceType = typeof(T);

// I assume MyContainer is wrapping an actual DI container, so
// resolve the implementation type for T from it:
T implementingObject = _myUnderlyingContainer.Resolve<T>();
Type implementingType = implementingObject.GetType();

// Get string representations of the passed-in Actions: this one is
// over to you :)
string beforeMethodCode = GetExpressionText(beforeMethodCall);
string afterMethodCode = GetExpressionText(afterMethodCall);

// Loop over all the interface's methods and create source code which
// contains a method with the same signature which calls the 'before'
// method, calls the proxied object's method, then calls the 'after'
// method:
string methodImplementations = string.Join(
Environment.NewLine,
interfaceType.GetMethods().Select(mi =>
{
const string methodTemplate = @"
public {0} {1}({2})
{{
{3}
this._wrappedObject.{1}({4});
{5}
}}";
// Get the arguments for the method signature, like
// 'Type1' 'Name1', 'Type', 'Name2', etc.
string methodSignatureArguments = string.Join(
", ",
mi.GetParameters()
.Select(pi => pi.ParameterType.FullName + " " + pi.Name));

// Get the arguments for the proxied method call, like 'Name1',
// 'Name2', etc.
string methodCallArguments = string.Join(
", ",
mi.GetParameters().Select(pi => pi.Name));

// Get the method return type:
string returnType = (mi.ReturnType == typeof(void)) ?
"void"
:
mi.ReturnType.FullName;

// Create the method source code:
return string.Format(
CultureInfo.InvariantCulture,
methodTemplate,
returnType, // <- {0}
mi.Name, // <- {1}
methodSignatureArguments, // <- {2}
beforeMethodCode, // <- {3}
methodCallArguments, // <- {4}
afterMethodCode); // <- {5}
}));

// Our proxy type name:
string proxyTypeName = string.Concat(implementingType.Name, "Proxy");

const string proxySourceTemplate = @"
namespace Proxies
{{
public class {0} : {1}
{{
private readonly {1} _wrappedObject;

public {0}({1} wrappedObject)
{{
this._wrappedObject = wrappedObject;
}}
{2}
}}
}}";

// Get the proxy class source code:
string proxySource = string.Format(
CultureInfo.InvariantCulture,
proxySourceTemplate,
proxyTypeName, // <- {0}
interfaceType.FullName, // <- {1}
methodImplementations); // <- {2}

// Create the proxy in an in-memory assembly:
CompilerParameters codeParameters = new CompilerParameters
{
MainClass = null,
GenerateExecutable = false,
GenerateInMemory = true,
OutputAssembly = null
};

// Add the assembly that the interface lives in so the compiler can
// use it:
codeParameters.ReferencedAssemblies.Add(interfaceType.Assembly.Location);

// Compile the proxy source code:
CompilerResults results = new CSharpCodeProvider()
.CompileAssemblyFromSource(codeParameters, proxySource);

// Create an instance of the proxy from the assembly we just created:
T proxy = (T)Activator.CreateInstance(
results.CompiledAssembly.GetTypes().First(),
implementingObject);

// Hand it back:
return proxy;
}

关于c# - 我如何为公共(public)接口(interface)类型编写我自己的装饰器实用程序(动态代理如何工作)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6716132/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com