【问题标题】:How to print the flow of execution of a program in c#如何在c#中打印程序的执行流程
【发布时间】:2018-05-18 17:08:02
【问题描述】:

我试图了解如何打印程序的执行流程。 我写了一些简单的代码来证明我的困境。

我希望它打印如下内容: 在 A 类,主要。 在 B 类中,方法 B。 在 C 类中,方法 C。

StackTrace 似乎给了我很多难以阅读的信息。有没有更简单的方法,或者更容易阅读 StackTrace 的方法?实际代码要大得多,我不想在每个方法中都添加打印语句,所以我认为这样的事情可能会使调试更容易。另外,我不能在实际代码中使用 Visual Studio 的调试器。因此,如果你们可以建议我使用哪个函数,如果不是 StackTrace,它将为我打印必要的信息,我将不胜感激。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace StackTrace
{
        public class A
        {
            public static void Main(string[] args)
            {
                B newB = new B();
                newB.methodB();
                Console.WriteLine("StackTrace: {0}", Environment.StackTrace); //I'd like to get the entire execution flow printed here
                Console.ReadKey(); //just for testing, don't worry about this.
            }
        }

        public class B
        {

            public void methodB()
            {
                C newC = new C();
                //Console.WriteLine("In class B, method B");
                newC.methodC();
            }
        }

        public class C
        {
            public void methodC()
            {
                //Console.WriteLine("In class C, method C");
            }
        }
}

【问题讨论】:

  • 您在使用 Visual Studio 吗?如果是这样,请在 main() 的第一行按 f9,然后单击 f10 单步执行代码。
  • 是的,我正在使用 Visual Studio。只是想澄清一下:我不能在实际代码中使用调试器。
  • @tim 够公平的。您可以使用 PostSharp 执行此操作,但免费版本有限。
  • 老实说,您最好的选择是学习如何阅读 StackTrace,因为您似乎正在寻找的所有信息都在其中。它只是格式很差。
  • 你可以考虑使用 Postsharp 之类的东西。添加一个横切关注点来记录正在执行的方法,并让 Postsharp 将该记录代码注入到每个方法中。

标签: c# embedded execution


【解决方案1】:

使用 postsharp 的免费版本,您可以很容易地做到这一点。首先,创建一个可以标记到方法的属性:

[PSerializable]
public class LogInvocationAttribute : MethodInterceptionAspect
{
    public override void OnInvoke(MethodInterceptionArgs args)
    {
        // TODO: use your existing logging method here. simple example here for now.
        Console.WriteLine($"{args.Instance.GetType()}.{args.Method.Name}");             

        // pass the call through to the original receiver
        args.Proceed();
    }
}

之后,任何你想记录的方法都可以像这样应用这个属性:

[LogInvocation]
public void SomeMethod(int someArg)
{
    // do stuff
}

使用 postsharp 的付费版本,您实际上可以在基类级别应用这样的东西,并让它也自动应用于子级(SO 参考 here)但是对于您想要将属性应用到您的方法的操作是获得您想要的东西的简单方法。

【讨论】:

  • 感谢您的示例!既然大家都在提倡PostSharp,那我就来看看。谢谢!
【解决方案2】:

因此,对于所有回复我的原始帖子的人来说,您可能会对我到目前为止的想法感兴趣。也许你们,或者其他人,可以加入这个讨论,我们可以找到一个更持久的解决方案。 但是,这是我最接近自动化的方法:

1) 创建这个函数/方法并将其添加到每个类中:

public void LogInfo(string className, string methodName)
{
   string info = ("In class: " + className + " In method: " + methodName);
   Console.WriteLine(info);
}

2) 将此行粘贴到代码库的相关区域:

 StackTrace stackTrace = new StackTrace();
 LogInfo(MethodBase.GetCurrentMethod().DeclaringType.Name, stackTrace.GetFrame(0).GetMethod().Name);

3) 另外请看一下我修改后的代码,注意我们需要添加这两个用例:
using System.Diagnostics; 使用 System.Reflection;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


using System.Diagnostics;
using System.Reflection;

namespace StackTraceTest
{
        public class A
        {
            public static void Main(string[] args)
            {
                StackTrace stackTrace = new StackTrace();
                LogInfo(MethodBase.GetCurrentMethod().DeclaringType.Name, stackTrace.GetFrame(0).GetMethod().Name);

                B newB = new B();
                newB.methodB();

                LogInfo(MethodBase.GetCurrentMethod().DeclaringType.Name, stackTrace.GetFrame(0).GetMethod().Name);

                /*for (int i = 0; i < stackTrace.FrameCount;i++)
                {
                    LogInfo(stackTrace.GetFrame(i).GetType().Name, stackTrace.GetFrame(i).GetMethod().Name);
                }*/

                Console.ReadLine();
            }

            public static void LogInfo(string className, string methodName)
            {
                string info = ("In class: " +className +" In method: " +methodName);
                Console.WriteLine(info);
            }
        }

        public class B
        {

            public void methodB()
            {
                StackTrace stackTrace = new StackTrace();
                LogInfo(MethodBase.GetCurrentMethod().DeclaringType.Name, stackTrace.GetFrame(0).GetMethod().Name);

                C newC = new C();
                newC.methodC();
            }

            public void LogInfo(string className, string methodName)
            {
                string info = ("In class: " + className + " In method: " + methodName);
                Console.WriteLine(info);
            }
        }

        public class C
        {
            public void methodC()
            {
                StackTrace stackTrace = new StackTrace();
                LogInfo(MethodBase.GetCurrentMethod().DeclaringType.Name, stackTrace.GetFrame(0).GetMethod().Name);
                //Console.WriteLine("StackTrace: {0}", Environment.StackTrace);
            }

            public void LogInfo(string className, string methodName)
            {
                string info = ("In class: " + className + " In method: " + methodName);
                Console.WriteLine(info);
            }
        }
}

4) 现在的输出变成:

In class: A In method: Main
In class: B In method: methodB
In class: C In method: methodC
In class: A In method: Main

5) 我想向你们指出一些事情:我认为注释掉的 for 循环将是可以在一行中解决所有问题的灵丹妙药,但它给出了输出:

In class: StackFrame In method: Main
In class: StackFrame In method: _nExecuteAssembly
In class: StackFrame In method: ExecuteAssembly
In class: StackFrame In method: RunUsersAssembly
In class: StackFrame In method: ThreadStart_Context
In class: StackFrame In method: RunInternal
In class: StackFrame In method: Run
In class: StackFrame In method: Run
In class: StackFrame In method: ThreadStart

还要注意 C 类中注释掉的行: 如果您取消注释,它会正确地为您提供整个执行流程(不会发布结果,因为它包含个人信息)。但是,这意味着我需要深入挖掘代码,找到最后调用的方法,并将这行代码添加到其中。

6) 来源: How performant is StackFrame?

How can I find the method that called the current method?

C# getting its own class name

请让我知道你们的想法。谢谢。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-06-24
    • 2018-09-01
    • 2021-08-24
    • 1970-01-01
    • 2012-02-25
    • 1970-01-01
    • 2011-02-21
    相关资源
    最近更新 更多