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

c# – 如何为公共接口类型编写自己的装饰器实用程序(动态代理如何工作)?,第1张

概述我注意到有时整个框架的工作都存在于具有非常简单的基本情况(不是批评)的事物中.例如,您可以使用几行代码和哈希表创建服务定位器,也可以使用整个框架. 也就是说,我很好奇是否有一种同样简单的自己做装饰的方法. (如果我不恰当地使用这个模式的名称,请更正我,我对这个术语不感兴趣). 动机:我很好奇城堡动态代理的工作方式…… 你怎么能编写MyContainer.Get(之前的Action,之后的Actio 我注意到有时整个框架的工作都存在于具有非常简单的基本情况(不是批评)的事物中.例如,您可以使用几行代码和哈希表创建服务定位器,也可以使用整个框架.

也就是说,我很好奇是否有一种同样简单的自己做装饰的方法. (如果我不恰当地使用这个模式的名称,请更正我,我对这个术语不感兴趣).

动机:我很好奇城堡动态代理的工作方式……

你怎么能编写MyContainer.Get(之前的Action,之后的Action)?

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 foofooafter foo
解决方法 根据我的理解,至少有两种方法可以生成运行时代码 – 如果你习惯使用IL,你可以使用 Reflection.Emit,否则你可以使用 CSharpCodeProvider,它可以让你在运行时从字符串或一系列描述DOM样式代码的对象.

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

>它不包括将Lambda转换为字符串.据我所知,this can be done.
>每次调用创建一个新的编译器都不会很好;您可以基于每个接口类型缓存编译器.
>编译源代码后,您可以(并且应该)检查结果对象以确保编译工作:

这是代码:

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# – 如何为公共接口类型编写自己的装饰器实用程序(动态代理如何工作)?全部内容,希望文章能够帮你解决c# – 如何为公共接口类型编写自己的装饰器实用程序(动态代理如何工作)?所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/1228174.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-05
下一篇 2022-06-05

发表评论

登录后才能评论

评论列表(0条)

保存