在c#中是否有一种类型化的方式来声明方法名?

本文关键字:方式 类型化 声明 方法 一种 是否 | 更新日期: 2023-09-27 18:03:12

我有一些反射代码,我希望有一种方法将方法名绑定到类型,而不是通过字符串声明。

我有这样的接口:

interface IDoStuff<T> {
    void Do(T stuff);
}

然后我有这个代码:

object stuff = GotThisFromSomewhereElse();
object doer = GotThisFromSomewhereElseAlso();
var doMethodInfo = doer.GetType().GetMethod("Do");
doMethodInfo.Invoke(doer, new[] { stuff });

问题是我不能简单地做一个安全强制转换并调用它,因为它是泛型的,而且我实际上不知道T是什么类型。

这工作得很好,但是当我重命名方法时,我必须去更新这个,我并不过分担心,因为我有测试来确认所有这些工作,这可以防止不知道它的变化。

它真的很丑,我很好奇是否有一些圆滑的方法可以让这个类型,这样如果我改变它,ReSharper就会重命名。

我真的很喜欢这样的东西:

object stuff = GotThisFromSomewhereElse();
object doer = GotThisFromSomewhereElseAlso();
var doMethodInfo = doer.GetType().Methods.Do;
doMethodInfo.Invoke(doer, new[] { stuff });

提前感谢,请告诉我这在c#中是否可能。

在c#中是否有一种类型化的方式来声明方法名?

从c# 6开始,您将能够使用新的nameof语句来避免魔法字符串:

IDoStuff<object> dummy = null; // don't need a valid instance.
string methodName = nameof(dummy.Do) // yay! no magic strings.

EDIT: @31eee384在评论中指出,以上内容可以进一步简化如下:

string methodName = nameof(IDoStuff<object>.Do);

关于新的nameof语句,文档有这样的说法,这似乎非常符合OP试图完成的任务:

通常需要捕获方法的字符串名称。在重命名定义时,使用nameof有助于保持代码的有效性。在此之前,您必须使用字符串字面量来引用定义,这在重命名代码元素时是很脆弱的,因为工具不知道检查这些字符串字面量。


在c# 6之前,也可以通过使用表达式来避免魔术字符串,但它有点笨拙。下面是一个适合你的例子。

首先,编写以下扩展方法:
public static string GetMethodName<T>(this T instance, Expression<Action<T>> methodExpression)
{
    if (methodExpression.Body is MethodCallExpression)
    {
        return ((MethodCallExpression)methodExpression.Body).Method.Name;
    }
    else
    {
        throw new ArgumentException(string.Format("Invalid method expression: {0}", methodExpression.Body));
    }
}

然后你可以这样使用:

IDoStuff<object> dummy = null; // don't need a valid instance.
string methodName = dummy.GetMethodName(t => t.Do(null)); // yay! still no magic strings.

创建通用方法DoIt:

private void DoIt<T>(T stuff, IDoStuff<T> doer) {
    doer.Do(stuff);
}

并命名为:

 DoIt(GotThisFromSomewhereElse(), GotThisFromSomewhereElseAlso());

当然,GotThisFromSomewhereElseAlsoGotThisFromSomewhereElse也应该是泛型