C# MethodTimer.Fody 使用详解

总目录


前言

NET开发过程中,经常会使用Stopwatch 来测量方法的执行所需时间,以便了解代码的执行效率。这里介绍一个开源库:MethodTimer.Fody。它可以辅助我们更为方便快速的完成方法执行效率的测量。


一、MethodTimer.Fody 是什么?

  • 主页:https://github.com/Fody/MethodTimer
  • MethodTimer.Fody 是一个功能强大的库,可以用于测量 .NET 应用程序中的方法的执行时间。允许你在不修改代码的情况下,自动地测量和记录方法的执行时间。
  • 这个工具是基于.NET的 weaving 技术,通过修改IL(Intermediate Language,中间语言)代码来插入计时逻辑,从而在方法调用前后记录时间戳,进而计算出方法的执行时间。
  • 它使用 Fody 插件框架可以无缝集成到项目中,所以向代码中添加性能测量功能变得非常容易。

二、使用 MethodTimer.Fody

1. 安装与配置

1 安装 MethodTimer.Fody 程序包

2 引用该程序包后,重新生成项目,一般会在项目目录下会生成一个FodyWeavers.xml 文件,内容如下:

xml 复制代码
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
  <MethodTimer />
</Weavers>
  • 如果目录下生成FodyWeavers.xml文件,则在vs编辑器中显示所有文件,然后将FodyWeavers.xml文件 包括在项目中
  • 如目录下没生成FodyWeavers.xml文件,则自己新建一个FodyWeavers.xml文件,添加上面的代码即可

2. 使用

1. 指定方法计时

  • 给需要计时的方法添加[Time]特性即可
csharp 复制代码
    internal class Program
    {
        static void Main(string[] args)
        {
            new Program().SayHi();
            Console.WriteLine("测试方法执行结束");
            Console.ReadKey();
        }

        [Time]
        public void SayHi()
        {
            Console.WriteLine("Hi");
        }
    }
  • 运行结果

2. 类中所有方法计时

  • [Time]特性添加在Class
csharp 复制代码
    [Time]
    internal class Program
    {
        static void Main(string[] args)
        {
            new Program().SayHi();
            new Program().SayGoodBye();
            Console.WriteLine("测试方法执行结束");
            Console.ReadKey();
        }

        public void SayHi()
        {
            Console.WriteLine("Hi");
        }

        public void SayGoodBye()
        {
            Console.WriteLine("GoodBye");
        }
    }
  • 运行结果

3. 原理分析

  • 当我们给以下代码添加上特性
csharp 复制代码
    [Time]
    internal class Program
    {
        static void Main(string[] args)
        {
            new Program().SayHi();
            new Program().SayGoodBye();
            Console.WriteLine("测试方法执行结束");
            Console.ReadKey();
        }

        public void SayHi()
        {
            Console.WriteLine("Hi");
        }

        public void SayGoodBye()
        {
            Console.WriteLine("GoodBye");
        }
    }
  • 在Main 方法的第一行打断点然后F11逐语句调试,会发现会自动生成以下代码
csharp 复制代码
internal class Program
{
	private static void Main(string[] args)
	{
		Stopwatch stopwatch = Stopwatch.StartNew();
		try
		{
			new Program().SayHi();
			new Program().SayGoodBye();
			Console.WriteLine("测试方法执行结束");
			Console.ReadKey();
		}
		finally
		{
			stopwatch.Stop();
			Trace.WriteLine("Program.Main " + stopwatch.ElapsedMilliseconds + "ms");
		}
	}

	public void SayHi()
	{
		Stopwatch stopwatch = Stopwatch.StartNew();
		try
		{
			Console.WriteLine("Hi");
		}
		finally
		{
			stopwatch.Stop();
			Trace.WriteLine("Program.SayHi " + stopwatch.ElapsedMilliseconds + "ms");
		}
	}

	public void SayGoodBye()
	{
		Stopwatch stopwatch = Stopwatch.StartNew();
		try
		{
			Console.WriteLine("GoodBye");
		}
		finally
		{
			stopwatch.Stop();
			Trace.WriteLine("Program.SayGoodBye " + stopwatch.ElapsedMilliseconds + "ms");
		}
	}
}

当我们添加上了Time特性会自动的生成 Stopwatch 相关的代码 对 方法进行计时,并且将测量信息通过Trace.WriteLine 输出

二、自定义测量信息的输出

在上面的示例中我们发现,如果只是添加[Time]特性,计时信息只会在编辑器的【输出】窗口中进行打印输出,如果我们想要在控制台,或者在日志中输出该如何操作呢?

那么我们只需要定义一个静态类即可:

csharp 复制代码
    public static class MethodTimeLogger
    {
        //按时段输出
        public static void Log(MethodBase methodBase, TimeSpan elapsed, string message)
        {
            Console.WriteLine($"方法:{methodBase.Name} 耗时(时段):{elapsed}, 信息:{message}");
        }

        //按总毫秒数输出
        //public static void Log(MethodBase methodBase, long milliseconds, string message)
        //{
        //    Console.WriteLine($"方法:{methodBase.Name} 耗时(总毫秒数):{milliseconds}, 信息:{message}");
        //}
    }
  • MethodTimeLogger是MethodTimer.Fody 定义好的切入逻辑,不用去改动,只需要改动逻辑 Log 方法内的输出内容即可。

    • 不要改动MethodTimeLogger 这个类的名称
    • 不要改动Log 这个方法的名称
    • 自定义的内容卸载Log方法中即可。
  • 如果改动Log方法名称,会有报错信息

1. 使用MethodTimeLogger

具体示例:

csharp 复制代码
    [Time]
    internal class Program
    {
        static void Main(string[] args)
        {
            new Program().SayHi();
            new Program().SayGoodBye();
            Console.WriteLine("测试方法执行结束");
            Console.ReadKey();
        }


        public void SayHi()
        {
            Console.WriteLine("Hi");
        }

        public void SayGoodBye()
        {
            Console.WriteLine("GoodBye");
        }
    }


    public static class MethodTimeLogger
    {
        //按时段输出
        public static void Log(MethodBase methodBase, TimeSpan elapsed, string message)
        {
            Console.WriteLine($"方法:{methodBase.Name} 耗时(时段):{elapsed}, 信息:{message}");
        }

        //按总毫秒数输出
        //public static void Log(MethodBase methodBase, long milliseconds, string message)
        //{
        //    Console.WriteLine($"方法:{methodBase.Name} 耗时(总毫秒数):{milliseconds}, 信息:{message}");
        //}
    }

}

当我们定义了MethodTimeLogger 这个静态类的时候,会自动生成如下代码

csharp 复制代码
internal class Program
{
	private static void Main(string[] args)
	{
		Stopwatch stopwatch = Stopwatch.StartNew();
		try
		{
			new Program().SayHi();
			new Program().SayGoodBye();
			Console.WriteLine("测试方法执行结束");
			Console.ReadKey();
		}
		finally
		{
			stopwatch.Stop();
			string message = default(string);
			MethodTimeLogger.Log(MethodBase.GetMethodFromHandle((RuntimeMethodHandle)/*OpCode not supported: LdMemberToken*/, typeof(Program).TypeHandle), stopwatch.Elapsed, message);
		}
	}

	public void SayHi()
	{
		Stopwatch stopwatch = Stopwatch.StartNew();
		try
		{
			Console.WriteLine("Hi");
		}
		finally
		{
			stopwatch.Stop();
			string message = default(string);
			MethodTimeLogger.Log(MethodBase.GetMethodFromHandle((RuntimeMethodHandle)/*OpCode not supported: LdMemberToken*/, typeof(Program).TypeHandle), stopwatch.Elapsed, message);
		}
	}

	public void SayGoodBye()
	{
		Stopwatch stopwatch = Stopwatch.StartNew();
		try
		{
			Console.WriteLine("GoodBye");
		}
		finally
		{
			stopwatch.Stop();
			string message = default(string);
			MethodTimeLogger.Log(MethodBase.GetMethodFromHandle((RuntimeMethodHandle)/*OpCode not supported: LdMemberToken*/, typeof(Program).TypeHandle), stopwatch.Elapsed, message);
		}
	}
}

运行结果如下:

2. 其他

当我们需要传入相关信息的时候,可以使用如下:

csharp 复制代码
    internal class Program
    {
        static void Main(string[] args)
        {
            new Program().SayHi();
            Console.WriteLine("测试方法执行结束");
            Console.ReadKey();
        }

        [Time("计时测量")]
        public void SayHi()
        {
            Console.WriteLine("Hi");
        }
    }


    public static class MethodTimeLogger
    {
        //按时段输出
        public static void Log(MethodBase methodBase, TimeSpan elapsed, string message)
        {
            Console.WriteLine($"方法:{methodBase.Name} 耗时(时段):{elapsed}, 信息:{message}");
        }
    }

运行结果:


结语

希望以上内容可以帮助到大家,如文中有不对之处,还请批评指正。


参考资料:
MethodTimer.Fody 统计代码执行时间
C#测试开源运行耗时库MethodTimer.Fody

相关推荐
Matlab精灵几秒前
Matlab函数中的隐马尔可夫模型
开发语言·matlab·统计学习
Microsoft Word1 分钟前
c++基础语法
开发语言·c++·算法
数据小爬虫@3 分钟前
如何利用java爬虫获得淘宝商品评论
java·开发语言·爬虫
qq_1728055911 分钟前
RUST学习教程-安装教程
开发语言·学习·rust·安装
wjs202419 分钟前
MongoDB 更新集合名
开发语言
monkey_meng22 分钟前
【遵守孤儿规则的External trait pattern】
开发语言·后端·rust
legend_jz1 小时前
【Linux】线程控制
linux·服务器·开发语言·c++·笔记·学习·学习方法
tangliang_cn1 小时前
java入门 自定义springboot starter
java·开发语言·spring boot
程序猿阿伟1 小时前
《智能指针频繁创建销毁:程序性能的“隐形杀手”》
java·开发语言·前端
新知图书1 小时前
Rust编程与项目实战-模块std::thread(之一)
开发语言·后端·rust