C# 在每次调用接口实现之前和之后运行特定的方法

C# 在每次调用接口实现之前和之后运行特定的方法,c#,C#,我的目标是让方法init()和complete(result)在所选类的每个方法之前和之后运行。 类似于ASP.NET中的ActionFilterAttribute具有OnActionExecuting和OnActionExecuted方法,这些方法在应用它们之前和之后运行 我希望对多个接口应用相同的init()和complete(result)方法,我希望尽可能避免代码重复并使代码易于理解 据我所知,似乎没有一个优雅的解决方案。到目前为止,我有3种选择: 选项1: public int

我的目标是让方法
init()
complete(result)
在所选类的每个方法之前和之后运行。 类似于ASP.NET中的
ActionFilterAttribute
具有
OnActionExecuting
OnActionExecuted
方法,这些方法在应用它们之前和之后运行

我希望对多个接口应用相同的
init()
complete(result)
方法,我希望尽可能避免代码重复并使代码易于理解

据我所知,似乎没有一个优雅的解决方案。到目前为止,我有3种选择:

选项1:

    public interface MyImportantMethods
    {
        object f();
        object g();
    }

    public class MyClass : MyImportantMethods
    {
        public object f()
        {
            // Do things
        }

        public object g()
        {
            // Do things
        }
    }

    public class WrappedMyClass : MyImportantMethods
    {
        private MyImportantMethods ActualContent;

        public MyModifiedClass(MyImportantMethods actualContent)
        {
            this.ActualContent = actualContent;
        }

        public object f()
        {
            init();
            object result = this.ActualContent.f();
            complete(result);
            return result;
        }

        public object g()
        {
            init();
            object result = this.ActualContent.g();
            complete(result);
            return result;
        }
    }
    public interface MyImportantMethods
    {
        object f();
        object g();
    }


    class Wrapper: IDisposable
    {   
        public object result;
        public Wrapper()
        {
            init();
        }

        void Dispose()
        {
            complete(result);
        }
    }

    public class MyModifiedClass {
        private void f()
        {
            using (var wrapper = new Wrapper(() => completeF()))
            {
                // Do Things
                wrapper.result = result;
            }
        }

        private void g()
        {
            using (var wrapper = new Wrapper(() => completeG()))
            {
                // Do Things
                wrapper.result = result;
            }
        }
    }
    public abstract class MyImportantMethodsBase
    {
        public object f()
        {
            init();
            object result = this.fImplementation();
            complete(fResult);
            return result;
        }

        public object g()
        {
            init();
            object result = this.gImplementation();
            complete(result);
            return result;
        }

        private abstract object fImplementation();

        private abstract object gImplementation();
    }

    public class MyModifiedClass : MyImportantMethodsBase {
        private object void fImplementation()
        {
            // Do Things
        }

        private object gImplementation()
        {
            // Do Things
        }
    }
  • 优点:带有实现的类与 调用
    init()
    complete()
    的函数,因此更具可读性和灵活性 更容易理解
  • 缺点:不熟悉代码的人很容易使用 错了。需要为我想要的每个接口使用不同的类 把它应用到
选项2:

    public interface MyImportantMethods
    {
        object f();
        object g();
    }

    public class MyClass : MyImportantMethods
    {
        public object f()
        {
            // Do things
        }

        public object g()
        {
            // Do things
        }
    }

    public class WrappedMyClass : MyImportantMethods
    {
        private MyImportantMethods ActualContent;

        public MyModifiedClass(MyImportantMethods actualContent)
        {
            this.ActualContent = actualContent;
        }

        public object f()
        {
            init();
            object result = this.ActualContent.f();
            complete(result);
            return result;
        }

        public object g()
        {
            init();
            object result = this.ActualContent.g();
            complete(result);
            return result;
        }
    }
    public interface MyImportantMethods
    {
        object f();
        object g();
    }


    class Wrapper: IDisposable
    {   
        public object result;
        public Wrapper()
        {
            init();
        }

        void Dispose()
        {
            complete(result);
        }
    }

    public class MyModifiedClass {
        private void f()
        {
            using (var wrapper = new Wrapper(() => completeF()))
            {
                // Do Things
                wrapper.result = result;
            }
        }

        private void g()
        {
            using (var wrapper = new Wrapper(() => completeG()))
            {
                // Do Things
                wrapper.result = result;
            }
        }
    }
    public abstract class MyImportantMethodsBase
    {
        public object f()
        {
            init();
            object result = this.fImplementation();
            complete(fResult);
            return result;
        }

        public object g()
        {
            init();
            object result = this.gImplementation();
            complete(result);
            return result;
        }

        private abstract object fImplementation();

        private abstract object gImplementation();
    }

    public class MyModifiedClass : MyImportantMethodsBase {
        private object void fImplementation()
        {
            // Do Things
        }

        private object gImplementation()
        {
            // Do Things
        }
    }
  • 优点:不可能使用错误的类。可以用一个吗 如果我使用反射技巧,所有接口的IDisposable类

  • 缺点:一段时间内,代码看起来会更加杂乱和难以理解 新的读取器,特别是如果包装器的声明需要多个 行或包装器需要来自结果的多个参数(两个 在我的情况下是正确的)。还依赖调用方来设置结果

选项3:

    public interface MyImportantMethods
    {
        object f();
        object g();
    }

    public class MyClass : MyImportantMethods
    {
        public object f()
        {
            // Do things
        }

        public object g()
        {
            // Do things
        }
    }

    public class WrappedMyClass : MyImportantMethods
    {
        private MyImportantMethods ActualContent;

        public MyModifiedClass(MyImportantMethods actualContent)
        {
            this.ActualContent = actualContent;
        }

        public object f()
        {
            init();
            object result = this.ActualContent.f();
            complete(result);
            return result;
        }

        public object g()
        {
            init();
            object result = this.ActualContent.g();
            complete(result);
            return result;
        }
    }
    public interface MyImportantMethods
    {
        object f();
        object g();
    }


    class Wrapper: IDisposable
    {   
        public object result;
        public Wrapper()
        {
            init();
        }

        void Dispose()
        {
            complete(result);
        }
    }

    public class MyModifiedClass {
        private void f()
        {
            using (var wrapper = new Wrapper(() => completeF()))
            {
                // Do Things
                wrapper.result = result;
            }
        }

        private void g()
        {
            using (var wrapper = new Wrapper(() => completeG()))
            {
                // Do Things
                wrapper.result = result;
            }
        }
    }
    public abstract class MyImportantMethodsBase
    {
        public object f()
        {
            init();
            object result = this.fImplementation();
            complete(fResult);
            return result;
        }

        public object g()
        {
            init();
            object result = this.gImplementation();
            complete(result);
            return result;
        }

        private abstract object fImplementation();

        private abstract object gImplementation();
    }

    public class MyModifiedClass : MyImportantMethodsBase {
        private object void fImplementation()
        {
            // Do Things
        }

        private object gImplementation()
        {
            // Do Things
        }
    }
  • 优点:不可能使用错误的类。这个班有 实现与调用init()的实现完全不同 和complete(),因此更易于阅读和理解

    缺点:读者理解起来不那么简单


真的没有像
ActionFilterAttribute
那样简单易懂的方法来实现我的目标吗?

也许带有工厂模式的选项1就足够了:将构造函数设为私有,这样就不会被错误地使用。在同一个类中创建一个静态函数来构造subject对象,然后围绕它创建一个包装器对象,返回公共共享接口类型的包装器对象

然而,如果您有许多类要包装,那么运行时代码生成(或design time.tt代码生成)可以帮助您解决这个问题。调用WrapperGenerator.Create(newObject),其中T是接口,newObject是实现该接口的私有构造对象。Create函数反映在接口上,然后根据该接口动态创建一个新类,该类将围绕在基对象中找到的函数进行额外的函数调用。任何新创建的包装器类都将为同一接口缓存

class WrapperGenerator
{
    static Dictionary<Type,ConstructorInfo> cachedWrappers = new ...();
    public static T Create<T>(object wrappedObject)
    {
        ConstructorInfo wrapperConstructor = null;
        var found = cachedWrappers.TryGet(typeof(T), out wrapperConstructor);
        if (found)
        {
            return (T)wrapperConstructor.Invoke(wrappedObject);
        }

        //cachedWrapper not found
        wrapperConstructor = GenerateNewConstructor(typeof(T));
        cachedWrappers.Add(typeof(T), wrapperConstructor);

        return (T)wrapperConstructor.Invoke(wrappedObject);
    }

    static long Counter = 0;
    static ConstructorInfo GenerateNewConstructor(Type t)
    {
        var methodList = t.GetMethods(...);
        StringBuilder sb = new StringBuilder();
        sb.Append("namespace WrapperClasses {\r\n");
        var ClassName = "Wrapper" + Counter++;
        var InterfaceName = t.FullName;
        sb.AppendFormat("public class {0} {{\r\n", ClassName);
        sb.AppendFormat("{0} wrappedObject = null;\r\n", ClassName);
        sb.AppendFormat("public Wrapper{0}({1} wrappedObject) {"\r\n, ClassName, InterfaceName);
        sb.Append("   this.wrappedObject = wrappedObject;\r\n");
        sb.Append("}\r\n");
        foreach (var m in methodList)
        {
            sb.AppendFormat("public {0} {1}({2}) {{", m.ReturnType.., m.Name, ParameterDeclarationsSegment(m));
            sb.AppendFormat("    init();\r\n"); 
            sb.AppendFormat("    var result = wrappedObject.{0}({1});\r\n", m.Name, ParameterPassthroughSegment(m));    
            sb.AppendFormat("    complete(result);\r\n");   
            sb.Append("};\r\n");    
        }
        //ETC.. closing class and namespace
        var LoadedAssembly = Compiler.Compile(sb,...);
        var getWrapperType = LoadedAssembly.SearchType(ClassName);
        return getWrapperType.GetConstructors()[0];
    }
}
类包装生成器
{
静态字典cachedWrappers=new…();
公共静态T创建(对象wrappedObject)
{
ConstructorInfo wrapperConstructor=null;
var found=cachedWrappers.TryGet(typeof(T),out wrapper构造函数);
如果(找到)
{
return(T)wrapperConstructor.Invoke(wrappedObject);
}
//找不到CachedRapper
wrapperConstructor=GenerateNewConstructor(typeof(T));
Add(typeof(T),wrapperConstructor);
return(T)wrapperConstructor.Invoke(wrappedObject);
}
静态长计数器=0;
静态构造函数信息生成器构造函数(t型)
{
var methodList=t.GetMethods(…);
StringBuilder sb=新的StringBuilder();
sb.Append(“名称空间包装器类{\r\n”);
var ClassName=“包装器”+计数器++;
var InterfaceName=t.FullName;
sb.AppendFormat(“公共类{0}{{\r\n”,类名);
sb.AppendFormat(“{0}wrappedObject=null;\r\n”,类名);
sb.AppendFormat(“公共包装器{0}({1}wrappedObject){”\r\n,类名,接口名);
sb.Append(“this.wrappedObject=wrappedObject;\r\n”);
sb.Append(“}\r\n”);
foreach(methodList中的var m)
{
sb.AppendFormat(“public{0}{1}({2}{),m.ReturnType..,m.Name,ParameterDeclarationsSegment(m));
sb.AppendFormat(“init();\r\n”);
sb.AppendFormat(“var result=wrappedObject.{0}({1});\r\n”,m.Name,参数passthroughsegment(m));
sb.AppendFormat(“完成(结果);\r\n”);
sb.Append(“};\r\n”);
}
//ETC.关闭类和命名空间
var LoadedAssembly=Compiler.Compile(sb,…);
var getWrapperType=LoadedAssembly.SearchType(类名);
返回getWrapperType.GetConstructors()[0];
}
}

注意:您应该在cachedWrappers周围实现锁定。

也许使用工厂模式的选项1就足够了:将构造函数设置为私有,这样它就不会被错误地使用。在同一个类中创建一个静态函数来构造subject对象,然后在其周围创建一个包装器对象,返回一个类型为公共共享i面对面

但是,如果您有许多类要包装,运行时代码生成(或设计时.tt代码生成)可以帮助您完成其中T是接口,newObject是实现该接口的私有构造对象。创建函数反映在该接口上,然后根据该接口动态创建一个新类,该类将围绕基对象中找到的函数进行额外的函数调用。任何新创建的包装类都将d将被缓存到同一接口

class WrapperGenerator
{
    static Dictionary<Type,ConstructorInfo> cachedWrappers = new ...();
    public static T Create<T>(object wrappedObject)
    {
        ConstructorInfo wrapperConstructor = null;
        var found = cachedWrappers.TryGet(typeof(T), out wrapperConstructor);
        if (found)
        {
            return (T)wrapperConstructor.Invoke(wrappedObject);
        }

        //cachedWrapper not found
        wrapperConstructor = GenerateNewConstructor(typeof(T));
        cachedWrappers.Add(typeof(T), wrapperConstructor);

        return (T)wrapperConstructor.Invoke(wrappedObject);
    }

    static long Counter = 0;
    static ConstructorInfo GenerateNewConstructor(Type t)
    {
        var methodList = t.GetMethods(...);
        StringBuilder sb = new StringBuilder();
        sb.Append("namespace WrapperClasses {\r\n");
        var ClassName = "Wrapper" + Counter++;
        var InterfaceName = t.FullName;
        sb.AppendFormat("public class {0} {{\r\n", ClassName);
        sb.AppendFormat("{0} wrappedObject = null;\r\n", ClassName);
        sb.AppendFormat("public Wrapper{0}({1} wrappedObject) {"\r\n, ClassName, InterfaceName);
        sb.Append("   this.wrappedObject = wrappedObject;\r\n");
        sb.Append("}\r\n");
        foreach (var m in methodList)
        {
            sb.AppendFormat("public {0} {1}({2}) {{", m.ReturnType.., m.Name, ParameterDeclarationsSegment(m));
            sb.AppendFormat("    init();\r\n"); 
            sb.AppendFormat("    var result = wrappedObject.{0}({1});\r\n", m.Name, ParameterPassthroughSegment(m));    
            sb.AppendFormat("    complete(result);\r\n");   
            sb.Append("};\r\n");    
        }
        //ETC.. closing class and namespace
        var LoadedAssembly = Compiler.Compile(sb,...);
        var getWrapperType = LoadedAssembly.SearchType(ClassName);
        return getWrapperType.GetConstructors()[0];
    }
}
类包装生成器
{
静态字典cachedWrappers=new…();
公共静态T创建(对象wrappedObject)
{
ConstructorInfo wrapperConstructor=null;
var found=cachedRappers.TryGet(类型为(T),o