对现有类方法的前后操作

时间:2014-03-10 09:23:00

标签: c# inheritance action tracing

我是C#的新手,我需要帮助。 我需要为函数实现一系列包装器,除了原始方法之外还将执行前后动作。

这是我目前的做法(一个功能示例):

class A
{
       public StreamWriter Writer;


       public bool Writeln(string textToWrite)//wrapper for Writer.write(string)
       {
              PreAction();
              this.Writer.Write(textToWrite);
              PostAction();
       }

}

相关场景是 - 跟踪每个函数条目(因此post和pre的签名是void post()并通过反射迭代所有方法参数)。

我需要在许多类和函数上完成 - 所以包装每个类都很繁琐,如果它们改变了,我将需要多次重新打开代码。 我能想到的唯一解决方案(而不是组合 - 参见上面附带的代码)是继承StreamWriter并覆盖基本方法,但对于多个类和函数来说再次不是很漂亮,任何人都可以想到或知道不同的方式这样做?

BR, MOSH。

1 个答案:

答案 0 :(得分:0)

您可以编写一个包装类,并将其传递给要包装方法的任何类的构造函数,或者让该类自己创建包装类。

它仍然相当繁琐,但它确实让你把所有的包装器逻辑放到一个类中。

一个例子将澄清。 class Demo显示了如何使用包装器类。另请注意,包装器类允许您检测异常(同时确保仍然抛出异常)。

为简洁起见,省略了参数检查逻辑:

using System;
using System.IO;

namespace ConsoleApp1
{
    public sealed class Wrapper
    {
        public Wrapper(Action pre, Action<Exception> post)
        {
            _pre  = pre;
            _post = post;
        }

        public T Wrap<T>(Func<T> func)
        {
            try
            {
                _pre();
                T result = func();
                _post(null);
                return result;
            }

            catch (Exception exception)
            {
                _post(exception);
                throw;
            }
        }

        public void Wrap(Action action)
        {
            try
            {
                _pre();
                action();
                _post(null);
            }

            catch (Exception exception)
            {
                _post(exception);
                throw;
            }
        }

        private readonly Action _pre;
        private readonly Action<Exception> _post;
    }

    public sealed class Demo
    {
        public Demo(Wrapper wrapper)
        {
            _wrapper = wrapper;
        }

        public string Name()
        {
            return _wrapper.Wrap(() => "This is a name");
        }

        public void Write(string textToWrite)
        {
            _wrapper.Wrap(() => _writer.Write(textToWrite));
        }

        public void ThrowsException()
        {
            _wrapper.Wrap(() => {throw new InvalidOperationException("Test");});
        }

        private readonly Wrapper      _wrapper;
        private readonly StreamWriter _writer = new StreamWriter(Console.OpenStandardOutput());
    }

    sealed class Program
    {
        private void run()
        {
            var wrapper = new Wrapper
            (
                () => Console.WriteLine("Calling pre()"),
                ex => Console.WriteLine("Calling post(), exception = " + ((ex != null) ? ex.Message : "<none>"))
            );

            Demo demo = new Demo(wrapper);

            Console.WriteLine("Name = " + demo.Name());
            demo.Write("Some text to write");
            demo.ThrowsException();
        }

        private static void Main()
        {
            new Program().run();
        }
    }
}