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()
- 缺点:不熟悉代码的人很容易使用 错了。需要为我想要的每个接口使用不同的类 把它应用到
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类
- 缺点:一段时间内,代码看起来会更加杂乱和难以理解 新的读取器,特别是如果包装器的声明需要多个 行或包装器需要来自结果的多个参数(两个 在我的情况下是正确的)。还依赖调用方来设置结果
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