C#的变迁史 - C# 5.0 之调用信息增强篇

Caller Information

  CallerInformation是一个简单的新特性,包括三个新引入的Attribute,使用它们可以用来获取方法调用者的信息,

  这三个Attribute在System.Runtime.CompilerServices命名空间下,分别叫做CallerMemberNameAttribute,CallerFilePathAttribute和CallerLineNumberAttribute。

CallerMemberNameAttribute:用来获取方法调用者的名称
CallerFilePathAttribute:用来获取方法调用者的源代码文件路径
CallerLineNumberAttribute:用来获取方法调用者所在的行号

  简单看一个小例子:

using System;
using System.Runtime.CompilerServices;

class Program
{
    static void Main(string[] args)
    {
        DoProcessing();
        Console.ReadKey();
    }

    static void DoProcessing()
    {
        TraceMessage("Something happened.");
    }

    static void TraceMessage(string message,
            [CallerMemberName] string memberName = "",
            [CallerFilePath] string sourceFilePath = "",
            [CallerLineNumber] int sourceLineNumber = 0)
    {
        Console.WriteLine("message: " + message);
        Console.WriteLine("member name: " + memberName);
        Console.WriteLine("source file path: " + sourceFilePath);
        Console.WriteLine("source line number: " + sourceLineNumber);
    }
}

不用多说了,结果很清楚。


  不过需要注意,Caller Info的这些Attribute只能用在optional parameter上,也就是说要指定默认值的。
  此外对于CallerMemberNameAttribute需要多说一点,使用这个Attribute可以避免在程序中硬编码调用方的函数名,至于这个属性返回的名字一般是这样的:

调用方法的类型 获取的结果
方法,属性,事件 方法,属性或事件的名字
构造函数 字符串".ctor"
静态构造函数 字符串".cctor"
Finalize函数 字符串"Finalize"
用户自定义的操作 编译产生的名字,比如"op_Addition"
Attribute构造函数 应用此Attribute的成员函数名字。如果不是应用于成员的Attribute,比如说是应用于类型的Attribute,则使用其设置的默认值

 

  这个特性在WPF的MVVM模式中很有用。在WPF的MVVM设计模式中的viewmodel里,我们是用INotifyPropertyChanged接口去通知在viewmodel里的改变。具体实现中很多的Binding是通过字符串来标识的,当修改一个Property的名字的时候,有时候很可能会忘记更新通知中的字符串名字,使用这个新的CallerMemberNameAttribute就能避免这个问题。
  例如以前通常的一种实现是这样的:

public class EmployeeVM:INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
  
    public void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
  
    private string _name;
  
    public string Name
    {
        get { return _name; }
        set
        {
            _name = value;
            OnPropertyChanged("Name");
        }
    }  
}

这种实现中Property的名字"Name"是以字符串的形式来约定的,一旦这个Property被Rename后忘记改了此处,就会带来bug。使用新的Attribute以后就可以这么写了:

public class EmployeeVM:INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
  
    public void OnPropertyChanged([CallerMemberName] string propertyName=null)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
  
    private string _name;
  
    public string Name
    {
        get { return _name; }
        set
        {
            _name = value;
         OnPropertyChanged();
        }
    }
}

这么一来就不用硬编码了,简单。

 

posted @ 2014-04-21 13:11  沙场秋点兵  阅读(522)  评论(1编辑  收藏  举报