调用函数后隐式调用函数

时间:2018-10-31 07:47:02

标签: c# .net function call implicit

是否有可能实现像单元测试中那样的行为 您无法在其中注释的地方

[TestInitialize]

每次在

之前执行此功能
[TestMethod]

被执行。并且以相同的方式

[TestCleanup]

总是在TestMethod之后执行。

3 个答案:

答案 0 :(得分:2)

您不能开箱即用。您需要编写自己的执行代码,该代码使用反射来确定执行的内容和方式。下面,我将分享一个简单的示例。

首先,您需要使用属性来描述方法的类型。

class InitMethodAttribute : Attribute
{
   public InitMethodAttribute():base()
   { }
};

class CleanupMethodAttribute : Attribute
{
   public CleanupMethodAttribute() : base()
   { }
};

class RunMethodAttribute : Attribute
{
   public RunMethodAttribute() : base()
   { }
};

我们将在示例类中使用它。请注意,此示例中的所有方法都是私有的。可以通过反射来调用它们。另外,请注意,为简单起见,它们没有参数,也不返回任何内容。您可以解决此示例,并将其更改为也支持参数。

class Example
{
   [InitMethod]
   private void Init()
   {
      Console.WriteLine("Initializing...");
   }

   [InitMethod]
   private void InitMore()
   {
      Console.WriteLine("More initializing...");
   }

   [RunMethod]
   private void Run()
   {
      Console.WriteLine("Running...");
   }

   [CleanupMethod]
   private void Cleanup()
   {
      Console.WriteLine("Cleaning up...");
   }
}

下一类称为执行程序(executor),它获取一个对象并查看其类型,识别方法并查看其属性。最终,如果在任何方法上都找到了RunMethod属性,则该方法将被执行。在执行所有InitMethod装饰方法之前,以及在所有CleanupMethod装饰方法之后。

   static class Executor
   {
      public static void Run(object obj)
      {
         var type = obj.GetType();
         var methods = type.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);

         var initMethods = new List<MethodInfo>();
         var cleanMethods = new List<MethodInfo>();
         foreach (var method in methods)
         {
            var initattrs = method.GetCustomAttributes(typeof(InitMethodAttribute));
            var cleanattrs = method.GetCustomAttributes(typeof(CleanupMethodAttribute));

            if (initattrs != null && initattrs.Count() > 0)
               initMethods.Add(method);
            else if (cleanattrs != null && cleanattrs.Count() > 0)
               cleanMethods.Add(method);
         }

         foreach (var method in methods)
         {
            var runattrs = method.GetCustomAttributes(typeof(RunMethodAttribute));
            if(runattrs != null)
            {
               var runattr = runattrs.FirstOrDefault();
               if(runattr != null)
               {
                  foreach (var m in initMethods)
                     m.Invoke(obj, null);

                  method.Invoke(obj, null);

                  foreach (var m in cleanMethods)
                     m.Invoke(obj, null);
               }
            }
         }
      }
   }

以下程序将使用所有这些内容:

class Program
{
   static void Main(string[] args)
   {
      var example = new Example();
      Executor.Run(example);
   }
}

输出为:

Initializing...
More initializing...
Running...
Cleaning up...

答案 1 :(得分:0)

您要查找的内容称为Aspect Oriented Programming,但不幸的是(或不取决于您询问的人),C#没有实现任何本机机制来支持它。实现AOP引擎当然是可能的,但不是一件容易的事,您需要使用某种动态代理(相关问题:CodeConstruct和.NET Core: attributes that execute before and after method指出的How to make a simple dynamic proxy in C#;还有here's a nice article about the subject)。

答案 2 :(得分:0)

有两种替代解决方案。

其中之一是,您可以使用Template Methods,其中初始化和清除是在基类中定义的,而实现类仅实现DoWorkImpl方法。调用DoWork会调用Initialize,然后运行在继承类中实现的DoWorkImpl方法,并以Cleanup结尾。这在(伪)代码中看起来像这样:

public abstract class BaseClass
{
    public void DoWork()
    {
        Initialize();
        DoWorkImpl();
        CleanUp();
    }

    public abstract void DoWorkImpl();

    private void Initialize()
    {
       // Initialization code here.
    }

    private void Cleanup()
    {
       // Cleanup code here.
    }
}

另一种替代方法是使用Actions
这在(伪)代码中看起来像这样:

public void SurroundWithInitializeAndCleanup(Action actionToWrap)
{
    Initialize();
    actionToWrap();
    Cleanup();
}

private void Initialize()
{
    // Initialization code here.
}

private void Cleanup()
{
   // Cleanup code here.
}