2015-11-10 51 views
3

我在Visual Studio中使用通用處理器2013轉換C#方法名的文本

我所要做的是創建一個包含一個方法的名稱的URL,但我想的名字方法是真實的代碼,以便它不會被硬編碼,並且如果函數名稱被改變,則繼續執行。

如果我用C或C++這樣做,我就只是說:

#define GENERATE_REFERENCE(text) #text 

我真的不關心它形成爲一個方法調用,因爲我已經在這裏原型

「什麼我試圖做的僞代碼」,在C#:

public class MyClass { 
    public void SayHello (String name) 
    { 
    ... 
    } 

    public void GenerateLink() 
    { 
     url = "... "+GenerateReference(this.SayHello); 
     // url would be "... SayHello"; 

    } 
    public String GenerateReference(DataType method) 
    { 
     // Is there some way to do this? 
     return method.MethodName.ToString(); 
    } 
} 

我的問題比建議的重複問題get methodinfo from a method reference C#不同,因爲我的問題來自於一個地方的偉大無知的C#機制(新手)。可疑的重複問題意味着更高的理解水平遠遠超出我在我的問題中所展示的水平 - 我不知道問這個問題是否足夠。我從來沒有從我的搜索中找到這個答案。

+1

的[從一個方法參考C#得到的MethodInfo]可能的複製(http://stackoverflow.com/questions/9382216/get-methodinfo-from-a-method-reference-c-sharp) – juharr

回答

2

您可以在參數上使用CallerMemberNameAttribute以讓編譯器在早期版本的C#中爲您插入名稱。

以下是一個依靠重載獲得正確答案的示例。請注意,如果你的「真實」的方法都有着自己獨特的參數,你不需要虛擬超載,可避免QueryMethodNameHelper說法完全

// This class is used both as a dummy parameter for overload resolution 
// and to hold the GetMyName method. You can call it whatever you want 
class QueryMethodNameHelper 
{ 
    private QueryMethodNameHelper() { } 

    public static readonly QueryMethodNameHelper Instance = 
    new QueryMethodNameHelper(); 

    public static string GetMyName([CallerMemberName] string 
    name = "[unknown]") 
    { 
    return name; 
    } 
} 

class Program 
{ 
    // The real method 
    static void SayHello() 
    { 
    Console.WriteLine("Hello!"); 
    } 

    // The dummy method; the parameter is never used, but it ensures 
    // we can have an overload that returns the string name 
    static string SayHello(QueryMethodNameHelper dummy) 
    { 
    return QueryMethodNameHelper.GetMyName(); 
    } 

    // Second real method that has an argument 
    static void DoStuff(int value) 
    { 
    Console.WriteLine("Doing stuff... " + value); 
    } 

    // Dummy method can use default parameter because 
    // there is no ambiguity 
    static string DoStuff(QueryMethodNameHelper dummy = null) 
    { 
    return QueryMethodNameHelper.GetMyName(); 
    } 

    static void Main(string[] args) 
    { 
    string s = SayHello(QueryMethodNameHelper.Instance); 
    Console.WriteLine(s); 
    SayHello(); 

    string s2 = DoStuff(); 
    Console.WriteLine(s2); 
    DoStuff(42); 
    } 
} 

該樣品在注射編譯期字符串的好處(不存在查找元數據的運行時間開銷),但它確實要求您保持方法名稱同步(例如,如果您重命名「真實」SayHello,則還需要重命名助手SayHello)。幸運的是,如果您單擊「重命名重載」複選框,重構對話框將爲您執行此操作,但默認情況下它不會打開。

+0

這隻適用於如果你從SayHello調用GenerateReference,而不是這種情況... –

+0

我認爲如果我把這個CallerMemberNameAttribute調用放在GenerateReference中,它會在提出問題時工作。 – craigdfrench

+0

@silverglade僅當您從SayHello調用GenerateReference時,在您的示例中,您不是。 –

0

使用的System.Reflection(預C#6.0):

typeof(MyClass).GetMethod("SayHello").Name

或nameof爲C#6.0和更高:

nameof(SayHello)

+3

但這與使用「SayHello」沒有任何區別。你需要方法的名稱來獲取方法的名稱 – Liam

9

C#6引入了一個新的運營商稱爲nameof這消除了這些硬編碼的字符串與方法名稱。

可以按如下方式使用它:nameof(Class.Method)

+3

在c#6之前添加如何做到這一點 –

9

C#6

nameof(MyClass.SayHello) 

之前C#6

public static String GenerateReference<T>(Expression<Action<T>> expression) 
{ 
    var member = expression.Body as MethodCallExpression; 

    if (member != null) 
     return member.Method.Name; 

    throw new ArgumentException("Expression is not a method", "expression"); 
} 

GenerateReference<MyClass>(c => c.SayHello(null)); 

幸得https://stackoverflow.com/a/9382501/471321

+1

爲什麼不能以dup方式關閉而不是發佈答案? – juharr

+0

我不認爲你需要。泛型參數用於具有該方法的類。 –

+0

確實 - 評論被刪除 –

2

C#6.0不包括nameof特徵。 但是,知道您在VS2013和C#6.0中默認情況下未啓用;我建議使用System.Reflection

我會用這樣的東西。

System.Reflection.MethodBase.GetCurrentMethod().Name 

並根據需要傳遞方法的名稱作爲參數。

乾杯!

+1

我認爲GetCurrentMethod比OP想要的更具限制性。 –

3

這可能是您的用例最簡單的方法;

Action<string> del = this.SayHello; 
string ret = del.Method.Name; 
+0

這是一個很好的建議。它有兩個缺點(除'nameof'之外的所有解決方案) - 如果您更改'SayHello'的簽名,則會導致編譯器錯誤,並且還會產生運行時間開銷。這些可能是可以接受的缺點。 –

+0

考慮到OP爲服務調用生成url的用例,我會說編譯器錯誤實際上是一種好處,它使得這個非常明確。至於運行時開銷,我同意,但是除了諸如nameof或[CallerMemberName]之類的編譯時功能外,我認爲它與其他選項差不多。 –

+0

編譯器錯誤不會修復URL字符串,儘管它需要不同的參數。真的,我認爲正確的做法是有一個真實的單一來源,然後從中產生客戶端和服務器代碼......但這超出了原始問題。 –