2011-08-23 42 views
1

在許多情況下,人們需要一種表達,參數,聲明等。例如名稱:如何獲得C#中的任何表達式作爲字符串?

public abstract void Log(string methodName, string parameterName, string message); 

public void FooMethod(string value) 
{ 
    if (value == null) 
    { 
     this.Log("FooMethod", "value", "The value must be whatever..."); 
     throw new ArgumentNullException("value"); 
    } 

    if (value.Length < 5) 
    { 
     this.Log("FooMethod", "value.Length", "The value length must be whatever..."); 
     throw new ArgumentException("value"); 
    } 
} 

是否有可以像使用自動獲得這些字符串文字像例如與關鍵字的任何方式typeof(string)? 還是有一種基於反射的簡單和高性能的方法?

我不是在尋找一種方法來檢查和記錄這個參數(這實際上只是一個例子)。我正在尋找一種方法來獲取部分代碼,如string

下會更準確,可以通過編譯器進行檢查,並重構代碼時,也將考慮:

public void FooMethod(string value) 
{ 
    if (value == null) 
    { 
     this.Log(literal(this.FooMethod), literal(value), "The parameter '" + literal(value) + "' must be whatever..."); 
     throw new ArgumentNullException(literal(value));    
    } 

    if (value.Length < 5) 
    { 
     this.Log(literal(this.FooMethod), literal(value.Length), "The value length must be whatever..."); 
     throw new ArgumentException(literal(value)); 
    } 
} 
+0

您的第二個示例是僞造的。沒有代碼會在'throw'後執行。 – leppie

+0

感謝您的建議。我改變了這個例子。 –

回答

2

您可以爲所有可能的類型創建類似這樣的靜態方法。以下是方法名稱。

public static string GetString(Action obj) 
{ 
    return obj.Method.Name; 
} 

public static string GetString(Delegate obj) 
{ 
    return obj.Method.Name; 
} 
1

聽起來像是你需要StackTrace.GetFrame。此方法將爲您提供所需的StackFrame對象,您可以從中找到此信息。

看看下面的代碼示例

StackFrame fr = new StackFrame(1,true); 
StackTrace st = new StackTrace(fr); 
this.Log.WriteEntry(fr.GetMethod().Name, 
        fr.GetMethod().GetParameters()[0].Name, 
        "The value must be whatever..."); 

順便說一句,在你的第二個代碼示例的登錄方法調用永遠不會執行,因爲一個例外是調用之前拋出。除了finally塊中的代碼之外,拋出異常之後,方法中的任何代碼都不會執行。見this article

+0

不幸的是,獲得堆棧幀可能需要幾微秒甚至幾毫秒,並且這超過了預計持續時間的幾個數量級的magnitutude! –

0

這取決於你的目標是什麼。如果你想獲得運行時間值Martin Doms答案可能是解決方案。如果您希望能夠鏈接說ArgumentNullException到一個特定的參數名稱,並確保如果你改變了名稱,你可以使用重構,你可以做這樣的事情:

public static void NotNull<T>(Expression<Func<IEnumerable<T>>> exp) 
     { 
      var expBody = exp.Body as MemberExpression; 
       T value = exp.Compile().Invoke(); 
       if (value == null){ 
        string memberName; 
        if (expBody != null){ 
         memberName = expBody.Member.Name; 
        } else{ 
         memberName = "member"; 
        } 
        throw new ArgumentNullException(memberName, memberName + " cannot be null"); 
       } 
     } 

然後你可以使用它像這樣:

public void Method(string value){ 
    Ensure.NotNull(()=>value); 
} 

它將檢查值是否爲空,並且如果值爲null,則將適當的消息格式化爲ArgumentNullException。 如果你使用.NET 4.0,我會建議使用合約來代替這個東西。並不是說它實際上解決了您的特殊需求,但與文檔和靜態分析相比,使用合同進行論證檢查有很多好處,這與「舊式的方式」相比具有很多好處。

+0

其實我並不是在尋找解決方案來檢查價值,這已經可以通過代碼合同來完成。我正在尋找一種以字符串形式獲取部分代碼的方法。 –

+0

@matthias:在你的例子中,你正在檢查值,然後如果值是使用讓你在那裏的代碼的屬性的X,我認爲這是你的使用場景。這就是上面的代碼片斷所做的。您無法使用合約獲取名稱,您可以使用表達式。但正如我所說,這取決於你何時不會他們。如果你想運行時間值爲stackframe,如果你想檢查一個表達式,你需要將它表示爲一個表達式樹 –

相關問題