2015-06-12 2 views
1

У меня есть член, который выглядит так: MyClass.SpecialMethod() Мне нужно отправить имя этого метода как строку другому методу. Я знаю, что могу использовать TypeOf.GetMethods(..).Name, но .. будет жестко запрограммирован, и если имя SpecialMethod изменится, возникнут проблемы.Получите имя метода, указав его?

Так что я хочу сделать что-то вроде этого

TypeOf(MyClass).GetMethod(MyClass.SpecialMethod).Name 

Это Возможное, и если да, то каким образом?

Я знаю, что могу получить имя текущего метода внутри метода, но на этом этапе он до конца.

+6

Это звучит просто идеально подходит для использования C# 6 в новом 'nameof' ключевого слова. Стыдно, что он еще не доступен для вас. –

ответ

2

Если C# 6,0 является выбор, который вы можете использовать новый "nameof" ключевое слово

nameof(MyClass.SpecialMethod) 

Посмотрите здесь для получения дополнительной информации (раздел "Nameof Выражения")
https://msdn.microsoft.com/en-us/magazine/dn802602.aspx


EDIT:
Примеры использования артикула:

namespace CSharp6.Tests 
{ 
    [TestClass] 
    public class NameofTests 
    { 
    [TestMethod] 
    public void Nameof_ExtractsName() 
    { 
     Assert.AreEqual<string>("NameofTests", nameof(NameofTests)); 
     Assert.AreEqual<string>("TestMethodAttribute", 
     nameof(TestMethodAttribute)); 
     Assert.AreEqual<string>("TestMethodAttribute", 
     nameof(
     Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute)); 
     Assert.AreEqual<string>("Nameof_ExtractsName", 
     string.Format("{0}", nameof(Nameof_ExtractsName))); 
     Assert.AreEqual<string>("Nameof_ExtractsName", 
     string.Format("{0}", nameof(
     CSharp6.Tests.NameofTests.Nameof_ExtractsName))); 
    } 
    } 
} 
3

Если вы можете использовать nameof() как Jason suggested, тогда перейдите к нему.

Если вы не затем записать этот вспомогательный метод:

class MyClass { 
    public void SpecialMethod() { 
     var myName = WhatIsMyName(); 
    } 

    private static string WhatIsMyName([CallerMemberName] string name= "") { 
     return name; 
    } 
} 

MSDN Посмотреть подробности. Обратите внимание, что если метод вызова перегружен, вы получите его имя, но оно неоднозначно.

Он не поддерживается в старше C# версии (он был представлен в .NET 4.5). Если вам приходится иметь дело с ними, то вам, возможно, придется прибегнуть старый трюк стека ходить, чтобы проверить имя члена, примерно что-то вроде этого:

[MethodImpl(MethodImplOptions.NoInlining)] 
private static string WhatIsMyName() { 
    return new StackTrace().GetFrame(1).GetMethod().Name; 
} 

(обратите внимание [MethodImpl(MethodImplOptions.NoInlining)] для предотвращения встраивания, в противном случае, если этот вызов встраиваемые вас» будет пропускать (GetFrame(1) вместо GetFrame(0)) их метод, который вы хотите иметь имя.

Имейте в виде, что все эти методы (стек ходьбы, информация о вызывающем абоненте, выражение) на самом деле нужно явно сделать вызов другим способом, где nameof() - разрешено при компиляции. Это может быть большой разницей в производительности (в случае, если это проблема).

2

Существует Expression путь:

public static string GetName<TResult>(Expression<Func<TResult>> exp) 
{ 
    return GetName(exp != null ? exp.Body as MethodCallExpression : null); 
} 

public static string GetName(Expression<Action> exp) 
{ 
    return GetName(exp != null ? exp.Body as MethodCallExpression : null); 
} 

private static string GetName(MethodCallExpression mce) 
{ 
    if (mce == null) 
    { 
     throw new ArgumentNullException(); 
    } 

    return mce.Method.Name; 
} 

Обратите внимание, что это медленно ...

использовать его как:

string name = GetName(() => MyClass.SpecialMethod()); 

или, если метод имеет некоторые параметры, поставить некоторые значения, которые имеют правильный тип. Метод не выполняется, так что это не проблема:

string name = GetName(() => MyClass.SpecialMethod(null, 5, default(DateTime))); 
2

C# 6 nameof действительно аккуратный.

В настоящее время вы можете использовать атрибут CallerMemberName в .NET 4.5, но если это не доступно вам или имя не принадлежит вызывающему, вы можете извлечь имя из выражения. Someone уже сделал для этого утилиту. Ниже приводится его код. Он делает код refactoring-friendly.

Как это работает:

//Should return "Length", value type property 
StaticReflection.GetMemberName<string>(x => x.Length); 

//Should return "Data", reference type property 
StaticReflection.GetMemberName<Exception>(x => x.Data); 

//Should return "Clone", method returning reference type 
StaticReflection.GetMemberName<string>(x => x.Clone()); 

//Should return "GetHashCode", method returning value type 
StaticReflection.GetMemberName<string>(x => x.GetHashCode()); 

//Should return "Reverse", void method 
StaticReflection.GetMemberName<List<string>>(x => x.Reverse()); 

//Should return "LastIndexOf", method with parameter 
StaticReflection.GetMemberName<string>(x => x.LastIndexOf(',')); 

Его полный код:

public static class StaticReflection 
{ 
    public static string GetMemberName<T>(
     this T instance, 
     Expression<Func<T, object>> expression) 
    { 
     return GetMemberName(expression); 
    } 

    public static string GetMemberName<T>(
     Expression<Func<T, object>> expression) 
    { 
     if (expression == null) 
     { 
      throw new ArgumentException(
       "The expression cannot be null."); 
     } 

     return GetMemberName(expression.Body); 
    } 

    public static string GetMemberName<T>(
     this T instance, 
     Expression<Action<T>> expression) 
    { 
     return GetMemberName(expression); 
    } 

    public static string GetMemberName<T>(
     Expression<Action<T>> expression) 
    { 
     if (expression == null) 
     { 
      throw new ArgumentException(
       "The expression cannot be null."); 
     } 

     return GetMemberName(expression.Body); 
    } 

    private static string GetMemberName(
     Expression expression) 
    { 
     if (expression == null) 
     { 
      throw new ArgumentException(
       "The expression cannot be null."); 
     } 

     if (expression is MemberExpression) 
     { 
      // Reference type property or field 
      var memberExpression = 
       (MemberExpression) expression; 
      return memberExpression.Member.Name; 
     } 

     if (expression is MethodCallExpression) 
     { 
      // Reference type method 
      var methodCallExpression = 
       (MethodCallExpression) expression; 
      return methodCallExpression.Method.Name; 
     } 

     if (expression is UnaryExpression) 
     { 
      // Property, field of method returning value type 
      var unaryExpression = (UnaryExpression) expression; 
      return GetMemberName(unaryExpression); 
     } 

     throw new ArgumentException("Invalid expression"); 
    } 

    private static string GetMemberName(
     UnaryExpression unaryExpression) 
    { 
     if (unaryExpression.Operand is MethodCallExpression) 
     { 
      var methodExpression = 
       (MethodCallExpression) unaryExpression.Operand; 
      return methodExpression.Method.Name; 
     } 

     return ((MemberExpression) unaryExpression.Operand) 
      .Member.Name; 
    } 
} 
Смежные вопросы