虽然这里有很多基于反射的好答案,但最明显的答案却被忽略了,那就是在编译时使用编译器。
请注意,自 .NET 4.5 和 C# 5 以来,以下方法已得到支持。
事实上,编译器确实有一些获取此信息的支持,只是稍微绕了一个弯路,通过 CallerMemberNameAttribute 属性实现。这允许您让编译器注入调用方法的成员名称。还有两个类似的属性,但我认为一个示例更容易理解:
考虑下面这个简单的类:
public static class Code
{
[MethodImplAttribute(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static string MemberName([CallerMemberName] string name = null) => name;
[MethodImplAttribute(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static string FilePath([CallerFilePathAttribute] string filePath = null) => filePath;
[MethodImplAttribute(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static int LineNumber([CallerLineNumberAttribute] int lineNumber = 0) => lineNumber;
}
在这个问题的上下文中,你实际上只需要第一种方法,你可以像这样使用它:
public class Test : INotifyPropertyChanged
{
private string _myProperty;
public string MyProperty
{
get => _myProperty;
set
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(Code.MemberName()));
_myProperty = value;
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
现在,由于此方法仅将参数返回给调用者,因此很有可能完全内联,这意味着运行时实际代码将只获取包含属性名称的字符串。
示例用法:
void Main()
{
var t = new Test();
t.PropertyChanged += (s, e) => Console.WriteLine(e.PropertyName);
t.MyProperty = "Test";
}
输出:
MyProperty
属性代码在反编译时实际上看起来是这样的:
IL_0000 ldarg.0
IL_0001 ldfld Test.PropertyChanged
IL_0006 dup
IL_0007 brtrue.s IL_000C
IL_0009 pop
IL_000A br.s IL_0021
IL_000C ldarg.0
// important bit here
IL_000D ldstr "MyProperty"
IL_0012 call Code.MemberName (String)
// important bit here
IL_0017 newobj PropertyChangedEventArgs..ctor
IL_001C callvirt PropertyChangedEventHandler.Invoke (Object, PropertyChangedEventArgs)
IL_0021 ldarg.0
IL_0022 ldarg.1
IL_0023 stfld Test._myProperty
IL_0028 ret