通过指出方法来获取方法的名称



>我有一个看起来像这样的成员MyClass.SpecialMethod()我需要将此方法的名称作为字符串发送到另一个方法。我知道我可以使用TypeOf.GetMethods(..).Name但是..将被硬编码,如果 SpecialMethod 更改名称,就会出现问题。

所以我想做的是这样的

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

这是可能的,如果是这样,如何?

我知道我可以从方法内部获取当前方法的名称,但此时已经晚了。

如果你

能按照Jason的建议使用nameof(),那就去做吧。

如果不这样做,请编写此帮助程序方法:

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()编译时解析。这可能是性能上的巨大差异(以防万一)。

如果可以选择

C# 6.0,则可以使用新的"nameof"关键字

nameof(MyClass.SpecialMethod)

查看此处以获取更多信息("表达式名称"部分)
https://msdn.microsoft.com/en-us/magazine/dn802602.aspx


编辑:
文章中的示例用例:

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)));
    }
  }
}

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)));

C# 6 名称非常整洁。

现在,可以在 .NET 4.5 中使用 CallerMemberName 属性,但如果无法使用该属性,或者名称不是来自调用方,则可以从表达式中提取名称。有人已经为此制作了一个实用程序。以下是他的代码。它使代码重构友好。

工作原理:

//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;
    }
}

请尝试使用 c# 的来电者信息功能

请参考网址:https://msdn.microsoft.com/en-us/library/hh534540.aspx

相关内容

  • 没有找到相关文章

最新更新