2008-10-05 46 views

回答

4

實現這種事情的最好方法是使用攔截,有幾種方法可以做到這一點,儘管它們都有些侵入性。一個是從ContextBoundObject派生所有的對象。 Here是使用這種方法的一個例子。另一種方法是使用其中一個現有的AOP庫來實現這一點。像Castle Project這樣的動態代理就是其中的許多核心。這裏有幾個環節: Spring.Net PostSharp Cecil

可能有幾個人,我知道Castle Windsor,並Ninject無論在國際奧委會功能之上提供AOP功能。

一旦AOP就緒後,您只需編寫一個攔截器類,將關於調用方法的信息寫入log4net。

如果其中一個AOP框架能夠爲您提供這種功能,我其實不會感到驚訝。

3

你可以使用後之類的編譯Postsharp。來自網站的樣本談到設置一個跟蹤器來輸入/退出一個方法,這與你想要的非常相似。

4

我不知道您的實際需求是什麼,但這裏有一個廉租選項。這不正是「自動」,但您可以使用堆棧跟蹤剝離你的方式尋找,不會要求傳遞參數的信息 - 類似ckramer的建議有關攔截:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

using System.Diagnostics; 

namespace TracingSample 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      DoSomething(); 
     } 

     static void DoSomething() 
     { 
      LogEnter(); 

      Console.WriteLine("Executing DoSomething"); 

      LogExit(); 
     } 

     static void LogEnter() 
     { 
      StackTrace trace = new StackTrace(); 
      if (trace.FrameCount > 1) 
      { 
       string ns = trace.GetFrame(1).GetMethod().DeclaringType.Namespace; 
       string typeName = trace.GetFrame(1).GetMethod().DeclaringType.Name; 
       Console.WriteLine("Entering {0}.{1}.{2}", ns, typeName, trace.GetFrame(1).GetMethod().Name); 
      } 
     } 

     static void LogExit() 
     { 
      StackTrace trace = new StackTrace(); 
      if (trace.FrameCount > 1) 
      { 
       string ns = trace.GetFrame(1).GetMethod().DeclaringType.Namespace; 
       string typeName = trace.GetFrame(1).GetMethod().DeclaringType.Name; 
       Console.WriteLine("Exiting {0}.{1}.{2}", ns, typeName, trace.GetFrame(1).GetMethod().Name); 
      } 
     } 
    } 
} 

你可以結合類似與繼承上面的例子中,在基本型採用非虛擬公共成員來表示的操作方法,然後調用虛擬成員實際上做的工作:

public abstract class BaseType 
{ 
    public void SomeFunction() 
    { 

     LogEnter(); 
     DoSomeFunction(); 
     LogExit(); 
    } 

    public abstract void DoSomeFunction(); 
} 

public class SubType : BaseType 
{ 
    public override void DoSomeFunction() 
    { 
     // Implementation of SomeFunction logic here... 
    } 
} 

再次 - 沒有太多的「自動「關於這一點,但如果你不需要在每一個方法invoc上進行檢測,那麼它的工作就會受到限制通貨膨脹。

希望這會有所幫助。

+1

此代碼順利使用此代碼捕獲的參數值 http://stackoverflow.com/a/6928253/1267778。所以我有類似logService.LogEnter(arg1,arg2,arg3)。好東西 – parliament 2014-10-17 02:44:29

0

您可以使用CodePlex上的開源框架CInject,它具有LogInjector標記方法調用的進入和退出。

或者您可以按照本文中提到的步驟Intercepting Method Calls using IL並使用C#中的Reflection.Emit類創建自己的攔截器。

0

功能

要擴大Jared的答案,避免代碼重複和包括options for arguments

private static void LogEnterExit(bool isEnter = true, params object[] args) 
{ 
    StackTrace trace = new StackTrace(true); // need `true` for getting file and line info 
    if (trace.FrameCount > 2) 
    { 
     string ns = trace.GetFrame(2).GetMethod().DeclaringType.Namespace; 
     string typeName = trace.GetFrame(2).GetMethod().DeclaringType.Name; 
     string args_string = args.Length == 0 ? "" : "\narguments: [" + args.Aggregate((current, next) => string.Format("{0},{1};", current, next))+"]"; 
     Console.WriteLine("{0} {1}.{2}.{3}{4}", isEnter ? "Entering" : "Exiting", ns, typeName, trace.GetFrame(2).GetMethod().Name, args_string); 
    } 
} 

static void LogEnter(params object[] args) 
{ 
    LogEnterExit(true, args); 
} 

static void LogExit(params object[] args) 
{ 
    LogEnterExit(false, args); 
} 

使用

static void DoSomething(string arg1) 
{ 
    LogEnter(arg1); 
    Console.WriteLine("Executing DoSomething"); 
    LogExit(); 
} 

輸出

在控制檯中,這將是如果DoSomething以「blah」作爲012運行,則輸出

Entering Program.DoSomething 
arguments: [blah] 
Executing DoSomething 
Exiting Program.DoSomething