我经常想这样做:
public void Foo(Bar arg)
{
throw new ArgumentException("Argument is incompatible with " + name(Foo));
}
Run Code Online (Sandbox Code Playgroud)
因为如果我更改了Foo的名称,IDE也会重构我的错误消息,如果我将方法的名称(或任何其他类型的成员标识符)放在字符串文字中,将不会发生什么.我知道实现"名称"的唯一方法是使用反射,但我认为性能损失超过了可持续性增益,并且它不会涵盖所有类型的标识符.
括号之间的表达式的值可以在编译时计算(如typeof),并通过更改语言规范进行优化以成为一个字符串文字.你认为这是一个有价值的功能吗?
PS:第一个例子看起来问题只与例外有关,但事实并非如此.想想您可能想要引用类型成员标识符的每种情况.你必须通过字符串文字来做,对吗?
另一个例子:
[RuntimeAcessibleDocumentation(Description="The class " + name(Baz) +
" does its job. See method " + name(DoItsJob) + " for more info.")]
public class Baz
{
[RuntimeAcessibleDocumentation(Description="This method will just pretend " +
"doing its job if the argument " + name(DoItsJob.Arguments.justPretend) +
" is true.")]
public void DoItsJob(bool justPretend)
{
if (justPretend)
Logger.log(name(justPretend) + "was true. Nothing done.");
}
}
Run Code Online (Sandbox Code Playgroud)
更新:这个问题是在C#6之前发布的,但可能仍然适用于那些使用该语言的早期版本的人.如果您使用的是C#6,请查看nameof运算符,它与name上面示例中的运算符完全相同.
Mar*_*ell 11
好吧,你可以欺骗和使用类似的东西:
public static string CallerName([CallerMemberName]string callerName = null)
{
return callerName;
}
Run Code Online (Sandbox Code Playgroud)
和:
public void Foo(Bar arg)
{
throw new ArgumentException("Argument is incompatible with " + CallerName());
}
Run Code Online (Sandbox Code Playgroud)
在这里,所有工作都由编译器完成(在编译时),因此如果重命名方法,它将立即返回正确的内容.
如果您只想要当前的方法名称: MethodBase.GetCurrentMethod().Name
如果是一种类型 typeof(Foo).Name
如果你想要一个变量/参数/字段/属性的名称,有一个Expression小树
public static string GetFieldName<T>(Expression<Func<T>> exp)
{
var body = exp.Body as MemberExpression;
if (body == null)
{
throw new ArgumentException();
}
return body.Member.Name;
}
string str = "Hello World";
string variableName = GetFieldName(() => str);
Run Code Online (Sandbox Code Playgroud)
对于方法名称,它有点棘手:
public static readonly MethodInfo CreateDelegate = typeof(Delegate).GetMethod("CreateDelegate", BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(Type), typeof(object), typeof(MethodInfo) }, null);
public static string GetMethodName<T>(Expression<Func<T>> exp)
{
var body = exp.Body as UnaryExpression;
if (body == null || body.NodeType != ExpressionType.Convert)
{
throw new ArgumentException();
}
var call = body.Operand as MethodCallExpression;
if (call == null)
{
throw new ArgumentException();
}
if (call.Method != CreateDelegate)
{
throw new ArgumentException();
}
var method = call.Arguments[2] as ConstantExpression;
if (method == null)
{
throw new ArgumentException();
}
MethodInfo method2 = (MethodInfo)method.Value;
return method2.Name;
}
Run Code Online (Sandbox Code Playgroud)
当你打电话给他们,你必须指定一个兼容的委托类型(Action,Action<...>,Func<...>...)
string str5 = GetMethodName<Action>(() => Main);
string str6 = GetMethodName<Func<int>>(() => Method1);
string str7 = GetMethodName<Func<int, int>>(() => Method2);
Run Code Online (Sandbox Code Playgroud)
或者更简单地说,不使用表达式:-)
public static string GetMethodName(Delegate del)
{
return del.Method.Name;
}
string str8 = GetMethodName((Action)Main);
string str9 = GetMethodName((Func<int>)Method1);
string str10 = GetMethodName((Func<int, int>)Method2);
Run Code Online (Sandbox Code Playgroud)
C# 版本 6 引入了nameof运算符,其工作方式类似于name问题示例中描述的运算符,但有一些限制。以下是C# FAQ 博客中的一些示例和摘录中的一些示例和摘录:
(if x == null) throw new ArgumentNullException(nameof(x));\nRun Code Online (Sandbox Code Playgroud)\n\n\n\n\n您可以在 nameof 表达式中放置更复杂的点名称,但 \xe2\x80\x99s 只是为了告诉编译器在哪里查找:仅使用最终标识符:
\n
WriteLine(nameof(person.Address.ZipCode)); // prints "ZipCode"\nRun Code Online (Sandbox Code Playgroud)\n\n\n\n注意:自预览版构建以来,nameof 有一些小的设计更改。在预览中,不允许使用像上一个示例中那样的点表达式,其中 person 是范围内的变量。相反,您必须在类型中添加点。
\n