今天也要做这个功能,就百度一下,结果搜索到了自己的文章。一开始还没注意,当看到里面的一个注释的方法时,一开始还以为自己复制错了代码,结果仔细一看网页的文章,我去,原来是自己写的,写的确实不咋地。

把自己的文章的代码复制了下来,稍微改了一下,运行看了一下效果,然后仔细一看,计算的总时间不对,如下图:

上一篇文章的地址:https://www.cnblogs.com/guxingy/p/10142242.html

改了几个地方:

    /// <summary>
/// 拦截器
/// </summary>
public class CallingLogInterceptor : IInterceptor
{
private DateTime dt { get; set; }
private TimeSpan ts { get; set; } /// <summary>
/// 方法执行前
/// </summary>
/// <param name="invocation"></param>
private void PreProceed(IInvocation invocation)
{
dt = DateTime.Now;
} /// <summary>
/// 方法执行后
/// </summary>
/// <param name="invocation"></param>
private void PostProceed(IInvocation invocation)
{
ts = DateTime.Now - dt; Console.WriteLine($"方法名称:{invocation.Method.Name}" );
Console.WriteLine($"开始时间:{dt.ToString("yyyy-MM-dd HH:mm:ss fff")}");
Console.WriteLine($"结束时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}");
Console.WriteLine($"所用时间:{ts.TotalSeconds}"); MethodOperationInfo.Add(invocation, ts.TotalMilliseconds);
} /// <summary>
/// 拦截
/// </summary>
/// <param name="invocation"></param>
public void Intercept(IInvocation invocation)
{
this.PreProceed(invocation);
invocation.Proceed();//调用
this.PostProceed(invocation);
}
}
    /// <summary>
/// 测试类1
/// </summary>
public class Class5_test1
{
public virtual void test1()
{
test4();
test3();
test2();
}
public virtual void test2()
{
System.Threading.Thread.Sleep();
}
public virtual void test3()
{
System.Threading.Thread.Sleep();
}
public virtual void test4()
{
System.Threading.Thread.Sleep();
}
}
    public class MyProxyGenerator
{
/// <summary>
/// 创建一个代理对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T CreateProxy<T>() where T : class
{
ProxyGenerator generator = new ProxyGenerator();//代理
CallingLogInterceptor interceptor = new CallingLogInterceptor();//定义 拦截器
T entity = generator.CreateClassProxy<T>(interceptor);
return entity;
}
}
    public class Class2
{
public static void test1()
{
Class5_test1 entity = MyProxyGenerator.CreateProxy<Class5_test1>();
entity.test1();
MethodOperationInfo.ShowContainsDetail(); Console.Read();
}
}

说明:所有的测试,只是修改了一下Class5_test1 这个类给

测试1

    /// <summary>
/// 测试类1
/// </summary>
public class Class5_test1
{
public virtual void test1()
{
test2();
test3();
test4();
}
public virtual void test2()
{
System.Threading.Thread.Sleep();
}
public virtual void test3()
{
System.Threading.Thread.Sleep();
}
public virtual void test4()
{
System.Threading.Thread.Sleep();
}
}

问题:这里test1调用了test2、test3、test4,那么执行test1所用时间,应该是test2、test3、test4所用时间的总和,正确所用时间至少应该是6秒(1+2+3),结果这里输出的是3秒多,肯定不对。

测试2

    /// <summary>
/// 测试类1
/// </summary>
public class Class5_test1
{
public virtual void test1()
{
test4();
test3();
test2();
}
public virtual void test2()
{
System.Threading.Thread.Sleep();
}
public virtual void test3()
{
System.Threading.Thread.Sleep();
}
public virtual void test4()
{
System.Threading.Thread.Sleep();
}
}

问题:这里的test1方法的所用时间是1秒多,更不对了。

结论:

  测试1 和 测试2 的区别,只是在test1里面改变了test2、test3、test4的执行顺序,结果时间却迥然不同,更奇怪的是,test1的所用时间,更是莫名的接近调用的倒数第二个方法。

  测试1里面,test1的所用时间,很接近test4。

  测试2里面,test1的所用时间,很接近test2。

  反正就是所用时间,很接近 方法体里面 最后一个 调用的方法,原因找到了再补充,了解一下动态代理的原理或许就知道了,也获取是自己写错了,估计是第一种可能

乘着自己好奇,又测试了一下,看下面哦

    /// <summary>
/// 测试类1
/// </summary>
public class Class5_test1
{
public virtual void test1()
{
Console.WriteLine("开始执行test1");
test4();
test3();
test2();
Console.WriteLine("执行完成test1");
}
public virtual void test2()
{
System.Threading.Thread.Sleep();
}
public virtual void test3()
{
System.Threading.Thread.Sleep();
}
public virtual void test4()
{
System.Threading.Thread.Sleep();
}
}

主要是是在,test1方法里面添加了方法的执行情况, 输出 开始执行 和 执行完成。

找到原因了:拦截器对象只创建了一个,所以dt一直都是最后调用的那个方法的开始时间

      还是自己写的代码有问题啊

赋上 改好的全部代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; using Castle.Core.Interceptor;
using Castle.DynamicProxy;
using System.Reflection;
using Newtonsoft.Json;
using System.Security.Cryptography; namespace ConsoleApplication3
{
//原文:https://www.cnblogs.com/guxingy/p/10142242.html public class Class2
{
public static void test1()
{
Class5_test1 entity = MyProxyGenerator.CreateProxy<Class5_test1>();
entity.test1();
MethodOperationInfo.ShowContainsDetail();
}
} public class MyProxyGenerator
{
/// <summary>
/// 创建一个代理对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T CreateProxy<T>() where T : class
{
ProxyGenerator generator = new ProxyGenerator();//代理
CallingLogInterceptor interceptor = new CallingLogInterceptor();//定义 拦截器
T entity = generator.CreateClassProxy<T>(interceptor);
return entity;
}
} /// <summary>
/// 拦截器
/// </summary>
public class CallingLogInterceptor : IInterceptor
{
private DateTime dt { get; set; }
private TimeSpan ts { get; set; } /// <summary>
/// 方法执行前
/// </summary>
/// <param name="invocation"></param>
private void PreProceed(IInvocation invocation)
{
//创建一个唯一的标识
//创建一个对象,并记录开始时间 //dt = DateTime.Now;
//Console.WriteLine($"开始执行,方法名称:{invocation.Method.Name},开始时间:{dt.ToString("yyyy-MM-dd HH:mm:ss fff")}");
//Console.WriteLine(); MethodOperationInfo.SetStartTime(invocation);
} /// <summary>
/// 方法执行后
/// </summary>
/// <param name="invocation"></param>
private void PostProceed(IInvocation invocation)
{
//通用标识找到之前创建的那个对象,并记录结束时间 //ts = DateTime.Now - dt;
//Console.WriteLine($"执行完成,方法名称:{invocation.Method.Name}");
//Console.WriteLine($" 开始时间:{dt.ToString("yyyy-MM-dd HH:mm:ss fff")}");
//Console.WriteLine($" 结束时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}");
//Console.WriteLine($" 所用时间:{ts.TotalSeconds}");
//Console.WriteLine(); MethodOperationInfo.SetEndTime(invocation);
} /// <summary>
/// 拦截
/// </summary>
/// <param name="invocation"></param>
public void Intercept(IInvocation invocation)
{
this.PreProceed(invocation);
invocation.Proceed();//调用
this.PostProceed(invocation);
}
} /// <summary>
/// 扩展
/// </summary>
public static class IntExtension
{
public static string ToString(this object obj, int len, bool afterFill = true)
{
string name = obj.ToString();
//int count = len - name.Length;//不能用这个 汉字和英文占用的长度不同
int count = len - System.Text.Encoding.Default.GetBytes(name).Length; if (afterFill)
{
for (int i = ; i < count; i++)
{
name += " ";
}
return name; }
else
{
string value = "";
for (int i = ; i < count; i++)
{
value += " ";
}
value += name;
return value;
}
}
} /// <summary>
/// 操作日志
/// </summary>
public class MethodOperationInfo
{
public string NameSpaceName { get; set; }
public string ClassName { get; set; }
public string MethodName { get; set; }
public string Parameters { get; set; }
public string ParameterTypes { get; set; }
public double TotalMilliseconds { get; set; } public string Name { get; set; }
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public bool IsEnd { get; set; }//标识这个对象是否完成计算耗时 /// <summary>
/// 构造函数
/// </summary>
/// <param name="invocation"></param>
public MethodOperationInfo(IInvocation invocation)
{
StartTime = DateTime.Now;
NameSpaceName = invocation.TargetType.Namespace;
ClassName = invocation.TargetType.Name;
MethodName = invocation.Method.Name;//方法名
ParameterTypes = GetParameterTypes(invocation);//参数类型
Parameters = GetParameter(invocation);//参数
Name = GetName(invocation);
IsEnd = false;
} /// <summary>
/// 操作完成
/// </summary>
/// <param name="invocation"></param>
public void OperationFinish(IInvocation invocation)
{
EndTime = DateTime.Now;
TotalMilliseconds = (EndTime - StartTime).TotalMilliseconds;
IsEnd = true;
} //存放 所有的 详细信息
public static List<MethodOperationInfo> operationInfos = new List<MethodOperationInfo>(); /// <summary>
/// 设置开始时间
/// </summary>
/// <param name="invocation"></param>
public static void SetStartTime(IInvocation invocation)
{
MethodOperationInfo model = new MethodOperationInfo(invocation);
operationInfos.Add(model);
} /// <summary>
/// 设置结束时间
/// </summary>
/// <param name="invocation"></param>
public static void SetEndTime(IInvocation invocation)
{
MethodOperationInfo model = GetModel(invocation);
model.OperationFinish(invocation);
} /// <summary>
/// 获取一个对象
/// </summary>
/// <param name="invocation"></param>
/// <returns></returns>
public static MethodOperationInfo GetModel(IInvocation invocation)
{
string name = GetName(invocation);
return operationInfos.Where(c => (c.Name == name) && !c.IsEnd).FirstOrDefault();
} /// <summary>
/// 获取 这个方法 唯一的编号,针对方法而已
/// </summary>
/// <param name="invocation"></param>
/// <returns></returns>
public static string GetName(IInvocation invocation)
{
string NameSpaceName = invocation.TargetType.Namespace;
string ClassName = invocation.TargetType.Name;
string MethodName = invocation.Method.Name;//方法名
string ParameterTypes = GetParameterTypes(invocation);
string Parameters = GetParameter(invocation);//参数 string strId = $"{NameSpaceName},{ClassName},{MethodName},{ParameterTypes}"; //MD5加密
byte[] result = Encoding.Default.GetBytes(strId);
MD5 md5 = new MD5CryptoServiceProvider();
byte[] output = md5.ComputeHash(result);
return BitConverter.ToString(output).Replace("-", "");
} /// <summary>
/// 获取方法的参数类型
/// 如:(System.String, System.Object, System.Int32)
/// </summary>
/// <param name="invocation"></param>
/// <returns></returns>
public static string GetParameterTypes(IInvocation invocation)
{
MethodInfo mInfo = invocation.Method;
ParameterInfo[] pInfos = mInfo.GetParameters(); string str = "";
str += "(";
for (int j = ; j < pInfos.Length; j++)
{
var p = pInfos[j];
string pTypeName = $"{p.ParameterType.ToString()}, ";
if (p.ParameterType.IsGenericType && (p.ParameterType.GetGenericTypeDefinition() == typeof(Nullable<>)))
{
pTypeName = $"{Nullable.GetUnderlyingType(p.ParameterType).Name}?, ";
}
str += pTypeName;
}
str = str.TrimEnd(' ').TrimEnd(',');
str += ")"; return str;
} /// <summary>
/// 获取方法的参数
/// </summary>
/// <param name="invocation"></param>
/// <returns></returns>
public static string GetParameter(IInvocation invocation)
{
string Parameters = "";//参数
if ((invocation.Arguments != null) && (invocation.Arguments.Length > ))
{
Parameters = JsonConvert.SerializeObject(invocation.Arguments);
}
return Parameters;
} /// <summary>
/// 显示日志
/// </summary>
/// <param name="ShowDetailRecord">是否显示详情记录-比较占用时间</param>
/// <param name="IsFilter">是否开启过滤</param>
public static void Show(bool ShowDetailRecord = true, bool IsFilter = false)
{
StringBuilder sb = new StringBuilder();
DateTime beforDT = DateTime.Now;
List<string> list_Show_Method = new List<string>() { "GetSingle_Value1" };//可改为配置参数 //每个方法-耗时
string str = "";
double totalMilliseconds_AllMethod = ; //去重
var operationInfos_NotRepeat = operationInfos.GroupBy(c => c.Name).Select(c => c.First()).ToList(); //分组统计
operationInfos.GroupBy(c => c.Name).Select(c => new
{
Name = c.Key,
ExecuteNumber = c.Count(),
TotalMilliseconds = c.Sum(a => a.TotalMilliseconds)
}).ToList().ForEach(c =>
{
var item = operationInfos_NotRepeat.Where(x => x.Name == c.Name).First();
totalMilliseconds_AllMethod += item.TotalMilliseconds; str += $"命名空间:{item.NameSpaceName.ToString(40)} ";
str += $"类名:{item.ClassName.ToString(30)} ";
str += $"方法:{item.MethodName.ToString(80)} ";
str += $"次数:{c.ExecuteNumber.ToString(10)} ";
str += $"耗时:{c.TotalMilliseconds.ToString(10, false) }毫秒 ";
str += $"\r\n";
});
sb.Append(str + "\r\n\r\n"); //方法-总耗时
str = "";
str += $"所有方法-耗时:{totalMilliseconds_AllMethod}毫秒 ";
str += $"{totalMilliseconds_AllMethod / 1000}秒 ";
str += $"{(totalMilliseconds_AllMethod / 1000 / 60).ToString("f2")}分钟 ";
str += $"当前时间:{DateTime.Now} ";
sb.Insert(, str + "\r\n\r\n"); #region 方法 每次耗时的 详情信息 if (ShowDetailRecord)
{
for (int i = ; i < operationInfos.Count; i++)
{
Console.WriteLine($"处理数据-当前行:{operationInfos.Count - i}");
var item = operationInfos[i]; //数据过滤
if (IsFilter && !list_Show_Method.Contains(item.MethodName))
{
continue;
} sb.Append($"命名空间:{item.NameSpaceName.ToString(40)} ");
sb.Append($"类名:{item.ClassName.ToString(30)} ");
sb.Append($"方法:{item.MethodName + item.ParameterTypes.ToString(80)} ");
sb.Append($"耗时:{item.TotalMilliseconds.ToString(10, false) }毫秒 ");
sb.Append($"参数:{item.Parameters.ToString(50)} ");
sb.Append($"\r\n");
}
}
#endregion //计算日志-耗时
sb.Insert(, $"计算日志-耗时:{DateTime.Now.Subtract(beforDT).TotalSeconds.ToString("#0.00000")}秒 \r\n\r\n"); System.IO.File.WriteAllText($"LOG_{DateTime.Now.ToString("yyyyMMddHHmmssfff")}.txt", sb.ToString());
Console.WriteLine("完成!");
} /// <summary>
/// 显示日志 包含详情数据
/// </summary>
public static void ShowContainsDetail()
{
Show(true);
} /// <summary>
/// 显示日志 不包含详情数据
/// </summary>
public static void ShowNotContainsDetail()
{
Show(false);
}
} /// <summary>
/// 测试类1
/// </summary>
public class Class5_test1
{
public virtual void test1()
{
Console.WriteLine("主方法-test1-开始执行");
Console.WriteLine(); for (int i = ; i < ; i++)
{
test4();
}
for (int i = ; i < ; i++)
{
test3();
}
for (int i = ; i < ; i++)
{
test2();
} Console.WriteLine("主方法-test1-执行完成");
Console.WriteLine();
}
public virtual void test2()
{
System.Threading.Thread.Sleep();
}
public virtual void test3()
{
System.Threading.Thread.Sleep();
}
public virtual void test4()
{
System.Threading.Thread.Sleep();
}
} }

但是当要代理的那个的类,如果没有无参构造函数,这种方法就还是用不了,准备解决这个问题,解决了到时候再贴上解决方案。

本来是准备用到生产环境测试一下自己的代码的,结果,我去,有参构造函数,接口,多态,麻蛋都有啊,改好了,再继续贴代码

C# 监测每个方法的执行次数和占用时间(测试4)的更多相关文章

  1. C# 监测每个方法的执行次数和占用时间(测试3)

    原文:http://www.cnblogs.com/RicCC/archive/2010/03/15/castle-dynamic-proxy.html 在Nuget引用 Castle.Dynamic ...

  2. C# 监测每个方法的执行次数和占用时间(测试2)

    在Nuget引用 Castle.DynamicProxy 和 Newtonsoft.Json 这个 原文:http://www.cnblogs.com/RicCC/archive/2010/03/15 ...

  3. C# 监测每个方法的执行次数和占用时间(测试1)

    在Nuget引用 Castle.DynamicProxy 和 Newtonsoft.Json 这个 原文:http://www.cnblogs.com/RicCC/archive/2010/03/15 ...

  4. C# 监测每个方法的执行次数和占用时间(测试5)

    又找到了一个bug 测试的类: public class Class11_1 { public virtual List<int> test2_1(List<tb_SensorRec ...

  5. 事件之onTouch方法的执行过程 及和 onClick执行发生冲突的解决办法

    转载:http://blog.csdn.net/jiangwei0910410003/article/details/17504315#quote 博主推荐: 风萧兮兮易水寒,“天真”一去兮不复还.如 ...

  6. Android中onTouch方法的执行过程以及和onClick执行发生冲突的解决办法

    $*********************************************************************************************$ 博主推荐 ...

  7. ORACLE查看SQL的执行次数/频率

    在ORACLE数据库应用调优中,一个SQL的执行次数/频率也是常常需要关注的,因为某个SQL执行太频繁,要么是由于应用设计有缺陷,需要在业务逻辑上做出优化处理,要么是业务特殊性所导致.如果执行频繁的S ...

  8. PLSQL_查询SQL的执行次数和频率(案例)

    2014-12-25 Created By BaoXinjian

  9. PLSQL_监控有些SQL的执行次数和频率

    原文:PLSQL_监控有些SQL的执行次数和频率 2014-12-25 Created By 鲍新建

随机推荐

  1. 1.将控制器添加到 ASP.NET Core MVC 应用

    模型-视图-控制器 (MVC) 体系结构模式将应用分成 3 个主要组件:模型 (M).视图 (V) 和控制器 (C). 模型(M):表示应用数据的类. 模型类使用验证逻辑来对该数据强制实施业务规则. ...

  2. java之spring mvc之Restful风格开发及相关的配置

    1. Restful : 表征状态状态转移. 传统 : url : http://localhost:8080/usersys/delete.do?user.id=12 Restful 风格:url ...

  3. 反射之关于MethodInfo的使用

    1.MethodInfo类是在System.Reflection命名空间底下,既然是在Reflection空间底下.故名思议关于反射相关的操作,其中比较重要的方法是Invoke()方法,它是加载相同程 ...

  4. 07、MySQL—时间日期类型

    时间日期类型 1.Date 日期类型:系统使用三个字节来存储数据,对应的格式为:YYYY-mm-dd,能表示的范围是从1000-01-01 到9999-12-12,初始值为0000-00-00 2.T ...

  5. 练习bloc , 动画

    有点意思, import 'package:flutter/material.dart'; import 'package:rxdart/rxdart.dart'; main()=>runApp ...

  6. Java中new和Class.forName的区别

    首先:New = Class.forName("pacage.A").newInstance(); new是关键字,直接创建对象.Class.forName()是一个方法,要求JV ...

  7. webpack练手项目之easySlide(三):commonChunks

    Hello,大家好. 在之前两篇文章中: webpack练手项目之easySlide(一):初探webpack webpack练手项目之easySlide(二):代码分割 与大家分享了webpack的 ...

  8. 使用EwoMail搭建属于自己的个人邮件服务器——超详细图文教程

    版权声明:本文为CSDN博主「C_成」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明.原文链接:https://blog.csdn.net/qq_41692307 ...

  9. js 数组 深拷贝 复制 (汇总)

    https://www.cnblogs.com/zhoupengyi/p/6048955.html https://www.cnblogs.com/racyily/p/3532176.html htt ...

  10. 【Flask】 python学习第一章 - 4.0 钩子函数和装饰器路由实现 session-cookie 请求上下文

    钩子函数和装饰器路由实现 before_request 每次请求都会触发 before_first_requrest  第一次请求前触发 after_request  请求后触发 并返回参数 tear ...