C# 如何跟踪排序后的方法调用?

C# 如何跟踪排序后的方法调用?,c#,.net,unity-interception,C#,.net,Unity Interception,我想按照顺序跟踪方法调用。因为日志记录将应用于生产,所以我不想对代码进行太多修改 到目前为止,我想在Unity上应用一个拦截器来跟踪方法调用,我几乎完成了。然而,日志打印出来并不是我所期望的。我需要的是: 来自peusedo代码,如下所示: void method1() { call method2(); } static void Main(string[] args) { var container = new UnityContain

我想按照顺序跟踪方法调用。因为日志记录将应用于生产,所以我不想对代码进行太多修改

到目前为止,我想在Unity上应用一个拦截器来跟踪方法调用,我几乎完成了。然而,日志打印出来并不是我所期望的。我需要的是:

来自peusedo代码,如下所示:

  void method1()
  {
     call method2();
  }
    static void Main(string[] args)
    {
        var container = new UnityContainer();
        container.RegisterType<IInterface1, Implementation1>();
        container.RegisterType<IInterface2, Implementation2>();
        container.RegisterInstance(typeof (IUnityContainer), container);
        container.AddNewExtension<Interception>();

        container.Configure<Interception>()
        .SetInterceptorFor<IInterface1>(new InterfaceInterceptor());

        container.Configure<Interception>()
        .SetInterceptorFor<IInterface2>(new InterfaceInterceptor());

        var service = container.Resolve<IInterface1>();
        var results = service.GetListCustomerIdByName("abc");

        Console.ReadLine();
     }

public interface IInterface1
    {
        [Trace]
        IEnumerable<Guid> GetListCustomerIdByName(string name);
    }

    public class Implementation1 : IInterface1
    {
        private readonly IInterface2 _impl;

        public Implementation1(IUnityContainer container)
        {
            _impl = container.Resolve<IInterface2>();
        }

        public IEnumerable<Guid> GetListCustomerIdByName(string name)
        {
            return _impl.GetListCustomerIdByName(name);
        }
    }

public interface IInterface2
{
    [Trace]
    IEnumerable<Guid> GetListCustomerIdByName(string name);
}

public class Implementation2 : IInterface2
{
    public IEnumerable<Guid> GetListCustomerIdByName(string name)
    {
        yield return Guid.NewGuid();
    }
}


public class TraceAttribute : HandlerAttribute
    {
        public override ICallHandler CreateHandler(IUnityContainer container)
        {
            return new TraceCallHandler();
        }
    }

public class TraceCallHandler : ICallHandler
{
    public IMethodReturn Invoke(IMethodInvocation input, 
   GetNextHandlerDelegate getNext)
    {
        Console.WriteLine("Entering " + input.MethodBase.Name +"()");

        InvokeHandlerDelegate next = getNext();

        IMethodReturn result = next(input, getNext);

        string returnValueStr = 
        result.ReturnValue == null ? "(void)" : result.ReturnValue.ToString();

        if (result.Exception != null)
        {
            Console.WriteLine("Exception: {0}", result.Exception);
        }

        Console.WriteLine("Leaving 
        " +input.MethodBase.Name + "() Return Value: [" + returnValueStr + "]");

        return result;
    }

    public int Order { get; set; }
}
跟踪日志的格式应如下所示:

正在输入方法调用1/ 输入方法调用2

离开方法调用2/ 离开方法调用1

顺便说一句,我的应用程序运行在.NETFramework版本4上

计划如下:

  void method1()
  {
     call method2();
  }
    static void Main(string[] args)
    {
        var container = new UnityContainer();
        container.RegisterType<IInterface1, Implementation1>();
        container.RegisterType<IInterface2, Implementation2>();
        container.RegisterInstance(typeof (IUnityContainer), container);
        container.AddNewExtension<Interception>();

        container.Configure<Interception>()
        .SetInterceptorFor<IInterface1>(new InterfaceInterceptor());

        container.Configure<Interception>()
        .SetInterceptorFor<IInterface2>(new InterfaceInterceptor());

        var service = container.Resolve<IInterface1>();
        var results = service.GetListCustomerIdByName("abc");

        Console.ReadLine();
     }

public interface IInterface1
    {
        [Trace]
        IEnumerable<Guid> GetListCustomerIdByName(string name);
    }

    public class Implementation1 : IInterface1
    {
        private readonly IInterface2 _impl;

        public Implementation1(IUnityContainer container)
        {
            _impl = container.Resolve<IInterface2>();
        }

        public IEnumerable<Guid> GetListCustomerIdByName(string name)
        {
            return _impl.GetListCustomerIdByName(name);
        }
    }

public interface IInterface2
{
    [Trace]
    IEnumerable<Guid> GetListCustomerIdByName(string name);
}

public class Implementation2 : IInterface2
{
    public IEnumerable<Guid> GetListCustomerIdByName(string name)
    {
        yield return Guid.NewGuid();
    }
}


public class TraceAttribute : HandlerAttribute
    {
        public override ICallHandler CreateHandler(IUnityContainer container)
        {
            return new TraceCallHandler();
        }
    }

public class TraceCallHandler : ICallHandler
{
    public IMethodReturn Invoke(IMethodInvocation input, 
   GetNextHandlerDelegate getNext)
    {
        Console.WriteLine("Entering " + input.MethodBase.Name +"()");

        InvokeHandlerDelegate next = getNext();

        IMethodReturn result = next(input, getNext);

        string returnValueStr = 
        result.ReturnValue == null ? "(void)" : result.ReturnValue.ToString();

        if (result.Exception != null)
        {
            Console.WriteLine("Exception: {0}", result.Exception);
        }

        Console.WriteLine("Leaving 
        " +input.MethodBase.Name + "() Return Value: [" + returnValueStr + "]");

        return result;
    }

    public int Order { get; set; }
}
static void Main(字符串[]args)
{
var container=new UnityContainer();
container.RegisterType();
container.RegisterType();
container.RegisterInstance(typeof(IUnityContainer),container);
container.AddNewExtension();
container.Configure()
.SetInterceptorFor(新接口interceptor());
container.Configure()
.SetInterceptorFor(新接口interceptor());
var service=container.Resolve();
var results=service.GetListCustomerIdByName(“abc”);
Console.ReadLine();
}
公共接口接口接口1
{
[跟踪]
IEnumerable GetListCustomerIdByName(字符串名称);
}
公共类实现1:IInterface1
{
专用只读接口2 _impl;
公共实现1(IUnityContainer容器)
{
_impl=container.Resolve();
}
公共IEnumerable GetListCustomerIdByName(字符串名称)
{
返回_impl.GetListCustomerIdByName(名称);
}
}
公共接口接口接口2
{
[跟踪]
IEnumerable GetListCustomerIdByName(字符串名称);
}
公共类实现2:IInterface2
{
公共IEnumerable GetListCustomerIdByName(字符串名称)
{
产生返回Guid.NewGuid();
}
}
公共类跟踪属性:HandlerAttribute
{
公共重写ICallHandler CreateHandler(IUnityContainer容器)
{
返回新的TraceCallHandler();
}
}
公共类TraceCallHandler:ICallHandler
{
公共IMethodReturn调用(IMethodInvoke输入,
GetNextHandlerElegate getNext)
{
Console.WriteLine(“输入”+input.MethodBase.Name+“()”;
InvokeHandlerDelegate next=getNext();
IMethodReturn结果=下一步(输入,获取下一步);
字符串returnValueStr=
result.ReturnValue==null?”(void)”:result.ReturnValue.ToString();
if(result.Exception!=null)
{
WriteLine(“异常:{0}”,result.Exception);
}
控制台。WriteLine(“离开
“+input.MethodBase.Name+”()返回值:[“+returnValueStr+”]”;
返回结果;
}
公共整数顺序{get;set;}
}

对不起,我的密码。它相当长

这里有一个类提供了该功能:

class Scope : IDisposable
{
    Action<string> _logger;
    string _memberName;

    public Scope(Action<string> logger, [CallerMemberName] string memberName = "N/A")
    {
        if (logger == null) throw new ArgumentNullException();

        _logger = logger;
        _memberName = memberName;

        _logger(string.Format("Entered {0}", _memberName));
    }

    public void Dispose()
    {
        _logger(string.Format("Exited {0}", _memberName));
    }
}
注意:如果使用不支持
[CallerMemberName]
属性的早期版本的C#,则必须显式提供
memberName

您还可以使用我在.NET 4.5之前的版本中使用的这个帮助器类:

public static class Here
{
    public static string Spot(HereOptions options)
    {
        return MakeMessageInternals(options, 3);
    }

    public static string Type
    {
        get
        {
            return MakeMessageInternals(HereOptions.Type, 3);
        }
    }

    public static string Member
    {
        get
        {
            return MakeMessageInternals(HereOptions.Member, 3);
        }
    }

    public static string FileLine
    {
        get
        {
            return MakeMessageInternals(HereOptions.FileLine, 3);
        }
    }

    public static string FileName
    {
        get
        {
            return MakeMessageInternals(HereOptions.FileName, 3);
        }
    }

    static StackFrame GetCaller(int index) { return new StackTrace(true).GetFrame(index); }

    static string MakeMessageInternals(HereOptions options, int index)
    {
        StackFrame first = null;
        var _FileName = new StringBuilder();
        var _FileLine = new StringBuilder();
        var _Member = new StringBuilder();
        var _Type = new StringBuilder();

        if ((options & HereOptions.FileName) == HereOptions.FileName)
        {
            first = GetCaller(index);
            if (first != null)
            {
                var fn = first.GetFileName();
                if (!string.IsNullOrEmpty(fn))
                    _FileName.Append(" " + Path.GetFileName(fn));
            }
        }

        if ((options & HereOptions.FileLine) == HereOptions.FileLine)
        {
            if (first == null)
                first = GetCaller(index);
            if (first != null)
            {
                var ln = first.GetFileLineNumber();
                _FileLine.Append(" #" + ln);
            }
        }

        if ((options & HereOptions.Member) == HereOptions.Member)
        {
            if (first == null)
                first = GetCaller(index);
            if (first != null)
            {
                var mn = first.GetMethod().Name;
                _Member.Append(" " + mn);
            }
        }

        if ((options & HereOptions.Type) == HereOptions.Type)
        {
            if (first == null)
                first = GetCaller(index);
            if (first != null)
            {
                var dt = first.GetMethod().DeclaringType;
                _Type.Append(string.Format(" ({0})", dt));
            }
        }

        var messageInternal = string.Format("{0}{1}{2}{3}",
            _FileName,
            _FileLine,
            _Member,
            _Type).Trim();

        return messageInternal;
    }
}

[Flags]
public enum HereOptions : byte
{
    None = 0,
    FileName = 1,
    FileLine = 2,
    Member = 4,
    Type = 8,
    All = 15
}

这意味着每次方法调用,我都会使用(范围记录器…我不确定如果里面有许多嵌套方法调用,它是否会打印出正确的方法调用顺序。无论如何,感谢您的努力。只要您不进行并行编程,它将打印出正确的方法调用,无论嵌套调用有多深。我自己使用了这个类的更复杂版本。我确实使用过没有找到更好的方法(有一种方法:使用PostSharp并使用面向方面的编程;但我不喜欢它)。对不起,我很失望!:)我不应用您的答案的另一个原因是您的代码仅适用于.Net framework 4.5版。我的代码运行在.Net framework 4.5版上。顺便说一句,我将+1,因为您的答案可能会有人从您的答案中得到帮助。我根据您的答案找出解决方法。我找到了解决CallerMemberName功能的链接。非常感谢您的帮助你的想法。我会接受这是一个正确的答案。我已经有了一个工具。我已经添加到了答案中。