Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 你将如何重构这段难闻的代码?(记录、复制和粘贴.Net 3.5)_C#_.net_.net 3.5_Refactoring - Fatal编程技术网

C# 你将如何重构这段难闻的代码?(记录、复制和粘贴.Net 3.5)

C# 你将如何重构这段难闻的代码?(记录、复制和粘贴.Net 3.5),c#,.net,.net-3.5,refactoring,C#,.net,.net 3.5,Refactoring,我有这样的代码: Logger logger = new Logger(); System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch(); logger.LogInformation("Calling SomeObject.SomeMethod at " + DateTime.Now.ToString()); stopWatch.Start(); // This is the method I'm int

我有这样的代码:

Logger logger = new Logger();
System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch();
logger.LogInformation("Calling SomeObject.SomeMethod at " + DateTime.Now.ToString());
stopWatch.Start();
// This is the method I'm interested in.
SomeResponse response = someObject.SomeMethod(someParam);
stopWatch.Stop();
logger.LogInformation("SomeObject.SomeMethod returned at " + DateTime.Now.ToString());
logger.LogInformation("SomeObject.SomeMethod took " + stopWatch.ElapsedMilliseconds + " milliseconds.");
void test()
{
  foo();
  //timer for the following statements
  using (new MyTimer("Some method"))
  {
    bar();
  }
  baz();
}
using (var t = new Timer())
{
   // your code
}
我需要围绕更多的对象及其方法编写类似的代码,以进行一些性能评测。我不允许使用第三方插件或软件等

我真的不想在所有这些方法调用和所有这些日志代码周围编写相同的代码。您将如何重构它以消除我的一些编码工作

如果我不是很清楚,请在评论中提出问题,我会尽力澄清


谢谢你的帮助

肯定是AOP的候选人。我们用PostSharp来做这类事情

为了简单起见,您可以使用泛型,就像这样(我不知道):

public T MyLogMethod(Func-someFunction,S-someParameter){

Func(S,T),其中S是方法的参数类型,T是返回类型。

您可以重构代码以接受方法指针实例(aka)

然后可以通过创建lambda表达式来调用它。由于myResponse是一个捕获的变量,因此将在运行此操作时填充它,并且myResponse将可供稍后在此范围内使用

SomeResponse myResponse = null;
CallWithLogTiming( () => myResponse = someObject.SomeMethod(someParam) );

我想我实现了一个计时器类,可以这样使用:

Logger logger = new Logger();
System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch();
logger.LogInformation("Calling SomeObject.SomeMethod at " + DateTime.Now.ToString());
stopWatch.Start();
// This is the method I'm interested in.
SomeResponse response = someObject.SomeMethod(someParam);
stopWatch.Stop();
logger.LogInformation("SomeObject.SomeMethod returned at " + DateTime.Now.ToString());
logger.LogInformation("SomeObject.SomeMethod took " + stopWatch.ElapsedMilliseconds + " milliseconds.");
void test()
{
  foo();
  //timer for the following statements
  using (new MyTimer("Some method"))
  {
    bar();
  }
  baz();
}
using (var t = new Timer())
{
   // your code
}
MyTimer类的实现如下所示:

  • 包含秒表实例和标识计时器的消息字符串
  • 构造函数启动秒表并记住消息字符串
  • Dispose方法停止秒表,并记录消息字符串和等待的时间

如果您编写这样的类(我使用的是Java;可能有一些东西无法准确翻译):

然后将每个方法中需要的代码减少到

myProfiler profiler = new myProfiler("SomeObject.SomeMethod");
profiler.Start();
...
profiler.Stop();
总有一个库允许您编写面向方面的代码。它可以让你做记录和秒表作为一个属性,这是很酷的。它将在方法中注入前置和后置代码,作为后编译步骤

进一步,您可以考虑这样的计时器/记录器静态方法来将您想要的代码包装为Time/log:

Timer.LogExecutionTime("SomeObject.SomeMethod", () =>
{
    Logger.LogBeforeAndAfter("SomeObject.SomeMethod", () =>
    {
        SomeResponse response = someObject.SomeMethod(someParam);
    }
});

您可以在Logger上使用一些简单的扩展方法使语法更清晰一些,这不需要额外的程序集,而只需要您已有的程序集,您可以立即将其插入。如果要在整个代码中多次这样做,那么它是可重用的

public static class LoggerExtentions
{
    public static void StartTimerLogInformation(this Logger logger, Stopwatch stopWatch, string method)
    {
        stopWatch.Reset();
        stopWatch.Start();
        logger.LogInformation(string.Format("Calling {0} at {1}", method, DateTime.Now.ToString()));
    }        

    public static void StopTimerLogInformation(this Logger logger, Stopwatch stopWatch, string method)
    {
        stopWatch.Stop();
        logger.LogInformation(string.Format("{0} returned at {1}", method, DateTime.Now.ToString()));
        logger.LogInformation(string.Format("{0} took {1} milliseconds", method, stopWatch.ElapsedMilliseconds));
        stopWatch.Reset();
    }
}
然后,您可以使用此代码替换您在原始帖子中的代码

Logger logger = new Logger();
Stopwatch stopWatch = new Stopwatch();
logger.StartTimerLogInformation(stopWatch, "SomeObject.SomeMethod");
SomeResponse response = someObject.SomeMethod(someParam);
logger.StopTimerLogInformation(stopWatch, "SomeObject.SomeMethod");

在所有对象上继承timer类怎么样?

在这些情况下,我喜欢使用一次性模式实现计时器;在发生错误时,您将保证正确的清理和记录:

    public class Timer : IDisposable
    {
        Logger logger = new Logger();
        Stopwatch stopWatch = new Stopwatch();

        public Timer()
        {
            calledFunc = CalledFunc;
            logger.LogInformation("Calling SomeObject.SomeMethod at " +
                DateTime.Now.ToString());
            stopWatch.Start();
        }

        // Dispose() calls Dispose(true)
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        // NOTE: Leave out the finalizer altogether if this class doesn't 
        // own unmanaged resources itself, but leave the other methods
        // exactly as they are. 
        ~Timer()
        {
            // Finalizer calls Dispose(false)
            Dispose(false);
        }
        // The bulk of the clean-up code is implemented in Dispose(bool)
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                // free managed resources
                stopWatch.Stop();
                logger.LogInformation("SomeObject.SomeMethod returned at " +
                    DateTime.Now.ToString());
                logger.LogInformation("SomeObject.SomeMethod took " +
                    stopWatch.ElapsedMilliseconds + " milliseconds.");
            }
            // free native resources if there are any.
        }
    }
然后您可以像这样使用计时器:

Logger logger = new Logger();
System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch();
logger.LogInformation("Calling SomeObject.SomeMethod at " + DateTime.Now.ToString());
stopWatch.Start();
// This is the method I'm interested in.
SomeResponse response = someObject.SomeMethod(someParam);
stopWatch.Stop();
logger.LogInformation("SomeObject.SomeMethod returned at " + DateTime.Now.ToString());
logger.LogInformation("SomeObject.SomeMethod took " + stopWatch.ElapsedMilliseconds + " milliseconds.");
void test()
{
  foo();
  //timer for the following statements
  using (new MyTimer("Some method"))
  {
    bar();
  }
  baz();
}
using (var t = new Timer())
{
   // your code
}


当然,您可以将参数传递给计时器(方法名、记录器等),以便自定义设置中发生的事情并进行处理

如果这是Java,我建议使用AspectJ。有没有一个与.Net相当的版本?有一个与.Net类似的版本,但我可能不被允许使用它。谢谢罗伯特,但我现在不被允许使用第三方代码。我认为值得向你的雇主询问。它是免费的,用户端不需要任何额外的东西。它只是在编译步骤中添加了额外的代码,使这类事情变得像向方法添加属性一样简单。如果没有其他内容,您可以在自己的本地副本上使用它,并确保在签入代码之前删除所有跟踪。屁股痛,但这会解决你的问题。好吧,我肯定会在家里开始玩postsharp!:)那很性感。可能会把我可怜的前Java同事搞糊涂。哈哈,这太酷了……把我搞糊涂了……你到底在那里干什么?:)在您的调用示例中()是什么意思?这是否意味着您在调用lambda块时没有向其中传递任何内容?在具有1个参数的lambda表达式中不需要paren,在具有0、2或更多参数的lambda表达式中需要paren。我很想尝试一下,但无法使其工作…David,您能用实际代码编辑吗?我总是在需要一个通用参数的操作上出错……我喜欢这样。简单易懂+1.