【问题标题】:Calling a function with Attribute使用属性调用函数
【发布时间】:2015-07-10 09:43:53
【问题描述】:

我有一个函数,它使用秒表的实例通过启动和停止来测量方法的时间。 我可以以某种方式在属性中定义该函数,然后用该属性装饰任何给定的方法来测量该方法的时间吗? 这将减少 LOC。 我不想使用任何第三方库。

public class AppTrace:BaseModel<AppTrace>
   {
    [DataMember]
    public string Comment;
    [DataMember]
    public string MethodName;
    [DataMember]
    public DateTime StartTimeStamp;
    [DataMember]
    public int Duration;
    [DataMember]
    public int UserObjectId;
    [DataMember]
    public string MachineName;
    [DataMember]
    public int ToolId;
    private System.Diagnostics.Stopwatch stpWatch;


    public AppTrace(string comment,string methodName,int userObjectId   ,string machineName = "",int? toolId=null)
    {
        MethodName = methodName;
        UserObjectId = userObjectId;
        StartTimeStamp = DateTime.UtcNow;
        Comment = comment;
        MachineName = machineName;

        stpWatch = new System.Diagnostics.Stopwatch();
        stpWatch.Start();
    }

    public AppTrace()
    {
    }

    public void CloseTrace()
    {
        this.stpWatch.Stop();
        Duration=Convert.ToInt32( this.stpWatch.ElapsedMilliseconds);
    }

}

如果没有属性,我可以在代表的帮助下做到这一点吗?

【问题讨论】:

  • 看看this thread,我想它回答了你的问题
  • 不,这是不可能的。您必须编写一些方法调用实用程序,它实际上将启动和停止StopWatch(例如Invoke.Measure(() =&gt; {/*do some stuff*/}))或改用一些AOP 框架(例如PostSharp,它在编译时使用IL 重写)。跨度>
  • 我正在该预定义函数中启动和停止秒表。
  • 我有一个启动秒表的功能和一个停止它的功能。现在,要测量任何给定方法的时间,我必须在前后调用这两个函数。那么,为了减少 loc,我可以使用属性吗?
  • 属性只能包含元信息,不能执行任何动作。而且即使你要定义这样一个属性,一些上层代码也必须通过反射找到它并以适当的方式使用。改用静态实用程序和 lambda 会更简单。

标签: c# methods attributes


【解决方案1】:

正如我在 cmets 中所说,一般来说这是不可能的。您可能会使用一些 AOP 框架,它可以相当成功地处理此类事情。或者编写一些调用实用程序。

在最简单的情况下,您的实用程序可能如下所示:

public static class Invoke 
{
    public static TimeSpan Measure(Action action)
    {
        if (action == null)
        { 
            throw new ArgumentNullException();
        }

        var stopWatch = Stopwatch.StartNew();
        action();
        stopWatch.Stop();

        return stopWatch.Elapsed;
    }  
}

然后您将能够测量方法调用时间。例如,Foo 类将用作测量目标。

// don't use such naming in production code
public class Foo
{
    public void DoWork1()
    {
        // imitating hard computations
        Thread.Sleep(TimeSpan.FromSeconds(5));
    }

    public void DoWork2(int param1) 
    {
        // imitating hard computations
        Thread.Sleep(param1);
    }
}

public static class Program
{
    public static void Main()
    {
        var foo = new Foo();

        // signature of foo.DoWork1 is suitable for Invoke.Measure, 
        //so you can use it as MethodGroup
        var time1 = Invoke.Measure(foo.DoWork1);
        Console.WriteLine("Time for 'DoWork1' is {0}s", time1.TotalSeconds);

        // signature of foo.DoWork2 is not suitable for Invoke.Measure,   
        // so you have to call it inside additional lambda 
        var time2 = Invoke.Measure(() => foo.DoWork2(42));
        Console.WriteLine("Time for 'DoWork2' is {0}s", time2.TotalSeconds);
    }
}

返回一些值但也可以实现的方法会更难。添加帮助类Timed&lt;T&gt;,它将包含返回值以及操作持续时间。

public class Timed<T>
{
    public readonly TimeSpan Duration;
    public readonly T Result;

    // making constructor private to force static factories usage
    private Timed(T result, TimeSpan duration) 
    {
        Result = result;
        Duration = duration;
    }

    // static factory method instead of constructor, for generic parameter 
    // type inference 
    public static Timed<T> Create(T result, TimeSpan duration) 
    {
        return new Timed<T>(result, duration);
    }
}

然后需要为Invoke.Measure 重载。

public static class Invoke 
{
    // Func<T> instead of Action
    public static Timed<T> Measure(Func<T> func)
    {
        if (func== null)
        { 
            throw new ArgumentNullException();
        }

        var stopWatch = Stopwatch.StartNew();
        var result = func();
        stopWatch.Stop();

        return Timed.Create(result, stopWatch.Elapsed);
    }  
}

顺便说一下F# REPL#time 指令来测量调用时间。您可以从F# 调用任何.NET 代码。它已集成到 Visual Studio 中,也可以从命令行 (fsi.exe) 调用。我不知道你的实际目标,所以它可能是合适的。

【讨论】:

  • 我不能将方法名称传递给 Attribute 属性,并在该属性中编写启动和停止的函数。让我添加这些功能。
  • 我可以使用委托来减少 LOC 吗?
  • 当然,你可以在属性中写一个方法,使用秒表测量函数计时。但是该函数不会被自动调用。所以你仍然需要编写一些代码来调用你的属性方法。我想这不值得麻烦。您可以将委托用于“逻辑”代码和静态助手,它们实际上会为您完成所有时间测量的繁琐工作。这就是我在回答中写的。此处无需添加任何内容。
猜你喜欢
  • 2014-06-18
  • 2016-02-25
  • 1970-01-01
  • 1970-01-01
  • 2019-09-02
  • 1970-01-01
  • 2011-07-25
  • 2019-01-15
  • 2021-12-15
相关资源
最近更新 更多