• 【翻译】C#获取方法调用信息


        看到这篇文章:http://tech.pro/tutorial/1155/obtaining-method-caller-information-in-c 感觉挺有用处,就节选重点翻译下。

        在日志组件中,我们可能需要记录方法调用信息。.NET 4.5/Visual Studio 2012提供了很方便地支持这一功能。

        要记录的方法调用信息包括:

    • 方法成员名称
    • 源文件路径
    • 行号

        为了获取这些信息,我们只需要使用System.Runtime.CompilerServices命名空间下的CallerMemberName、CallderFilePath和CallderLineNumber注解,如下:

    public static void Log(string msg, 
        [CallerMemberName] string memberName  = "", 
        [CallerFilePath] string filePath = "", 
        [CallerLineNumber] int lineNumber = 0)
    {
        string msgToLog = string.Format("{0} ({1} line {2}): {3}",
            memberName, filePath, lineNumber, msg);
        Trace.WriteLine(msgToLog);
    }

        然后我们在业务逻辑代码中这样调用:

    class BusinessLogic
    {
        public void PerformLogic()
        {
            // do logic
            Logger.Log("Finished performing logic.");
        }
    }

        运行之后我们可以看到下面输出:

    PerformLogic (c:\Project\Program.cs line 26): Finished performing logic.

        代码很简单,不多解释了。

    工作原理

        上面代码背后的工作原理是什么呢?概括成一句话:编译器帮了我们大忙!

        当编译器遇到某个方法的参数带有上面的注解时,参数的值被忽略,它将自动为其提供值。比如下面是上面的PerformLogic方法的反编译结果(IL代码):

    .method public hidebysig instance void  PerformLogic() cil managed
    {
      .maxstack  8
      IL_0000:  ldstr      "Finished performing logic."
      IL_0005:  ldstr      "PerformLogic"
      IL_000a:  ldstr      "c:\\Project\\Program.cs"
      IL_000f:  ldc.i4.s   26
      IL_0011:  call       void ConsoleApplication1.Logger::Log(string,
                                                                string,
                                                                string,
                                                                int32)
      IL_0016:  ret
    } // end of method BusinessLogic::PerformLogic

        我们可以看出方法名、源文件路径和行号都被标识为常量(在编译期间完成)。

        我们再来看一个例子:当属性值发生改变时通知改变。

        先定义一个事件处理接口:

    public interface INotifyPropertyChanged
    {
        event PropertyChangedEventHandler PropertyChanged;
    }

    接口定义了一个事件,当属性值发生改变时会触发这个事件。然后我们让要监听属性值变化的类实现这个接口:

    class Person : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
    
        private string firstName;
        private string lastName;
    
        public string FirstName
        {
            get { return this.firstName; }
            set
            {
                this.firstName = value;
                NotifyPropertyChanged("FirstName");
            }
        }
    
        public string LastName
        {
            get { return this.lastName; }
            set
            {
                this.lastName = value;
                NotifyPropertyChanged("LastName");
            }
        }
    
        private void NotifyPropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

        每当调用Person对象的FirstName或者LastName属性的setter方法时就会调用私有方法NotifyPropertyChanged方法,然后这个方法内部再触发属性改变事件。

        但是这里propertyName并不是必须的,如果我们使用[CallerMemberName]的话,如下:

    public string LastName
    {
        get { return this.lastName; }
        set
        {
            this.lastName = value;
            NotifyPropertyChanged();
        }
    }
    
    private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
    {
        if (this.PropertyChanged != null)
        {
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

        现在由编译器编译时自动帮我们设定propertyName的值。

        注意上面讲的特性必须在.NET 4.5/Visual Studio 2012及以上版本才支持,在此之前可以用下面的替代方案(但不推荐这种方案):

    public static void Log(string msg)
    {
        StackFrame stackFrame = new StackFrame(1);
        string methodName = stackFrame.GetMethod().Name;
        string fileName = stackFrame.GetFileName();
        int lineNumber = stackFrame.GetFileLineNumber();
    
        string msgToLog = string.Format("{0} ({1} line {2}): {3}",
            methodName, fileName, lineNumber, msg);
        System.Diagnostics.Trace.WriteLine(msgToLog);
    }
  • 相关阅读:
    NS2 nam中节点及数据流颜色设置
    JSF简单介绍
    深入浅出谈开窗函数(一)
    BZOJ2440(全然平方数)二分+莫比乌斯容斥
    怎样在SharePoint管理中心检查数据库架构版本号、修补级别和修补程序的常规监控
    Java实现BASE64编解码
    博弈 个人 见解
    【剑指offer】第一个仅仅出现一次的字符
    cocos2d基础篇笔记四
    SSL连接建立过程分析(1)
  • 原文地址:https://www.cnblogs.com/feichexia/p/3029177.html
Copyright © 2020-2023  润新知