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错误处理_C#_.net_Exception Handling - Fatal编程技术网

C# .NET错误处理

C# .NET错误处理,c#,.net,exception-handling,C#,.net,Exception Handling,我一直在编写.NET应用程序,对框架中包含的错误处理印象深刻 当捕捉到进程或代码中某个地方抛出的错误时,我喜欢包括消息(ex.message,这通常是非常一般的),但也包括stacktrace(ex.stacktrace),这有助于将问题追溯到特定的位置 举个简单的例子,比如说,我们在一个方法中将数字记录到日志中: public void ExampleMethod(int number){ try{ int num = number ...open co

我一直在编写.NET应用程序,对框架中包含的错误处理印象深刻

当捕捉到进程或代码中某个地方抛出的错误时,我喜欢包括消息(
ex.message
,这通常是非常一般的),但也包括stacktrace(
ex.stacktrace
),这有助于将问题追溯到特定的位置

举个简单的例子,比如说,我们在一个方法中将数字记录到日志中:

public void ExampleMethod(int number){
    try{
        int num = number
        ...open connection to file
        ...write number to file
    }
    catch(Exception ex){
        .... deal with exception (ex.message,ex.stacktrace etc...)
    }
    finally{
    ...close file connection
    }
}
是否有任何方法可以查看所调用的方法(在本例中为
ExampleMethod
),以及传递的可能导致方法调用崩溃的特定数字?我相信您可以在catch块中记录这一点,但我主要感兴趣的是捕获导致系统抛出异常的方法调用和参数


有什么想法吗?

您可以创建一个继承Exception的类,并向其添加一些参数,以便将数字传递给它。

如果您想知道方法中参数的值,那么只有一种方法,IMO,可以做到这一点-您需要用数据重新打包异常

例如:

 int param1 = 10;
 string param2 = "Hello World";

 try
 {
     SomeMethod(param1, param2)
 }
 catch(SomeExpectedException e)
 {
      throw new MyParameterSensitiveException(e, param1, param2);
 }

基本上,您将原始异常重新打包为另一个异常的内部异常,并另外提供用于调用该方法的参数。然后你可以通过某种方式检查,找出哪里出了问题

我建议将参数值填充到异常的
数据
字典中,例如

public void ExampleMethod(int number) {
try {
    int num = number
    ...open connection to file
    ...write number to file
}
catch(Exception ex) {
    ex.Data["number"] = number;
    //.... deal with exception (ex.message,ex.stacktrace etc...)
}
finally {
    //...close file connection
}
此方法的另一个优点是,您可以将参数填充到
catch
块中,然后重新抛出异常并将其记录到其他地方,而不会丢失堆栈跟踪,例如

catch(Exception ex) {
    ex.Data["number"] = number;
    throw;
}
为此,请执行以下操作:

public void MyProblematicMethod(int id, string name)
{
    try
    {
        object o = null;
        int hash = o.GetHashCode(); // throws NullReferenceException
    }
    catch (Exception ex)
    {
        string errorMessage = SummarizeMethodCall(MethodBase.GetCurrentMethod(), id, name);
        // TODO: do something with errorMessage
    }
}
…然后得到这个:

"MyProblematicMethod invoked: id = 1, name = Charlie"
…您可以这样做:

public static string SummarizeMethodCall(MethodBase method, params object[] values)
{
    var output = new StringBuilder(method.Name + " invoked: ");
    ParameterInfo[] parameters = method.GetParameters();
    for (int i = 0; i < parameters.Length; i++)
    {
        output.AppendFormat("{0} = {1}",
            parameters[i].Name,
            i >= values.Length ? "<empty>" : values[i]
        );
        if (i < parameters.Length - 1)
            output.Append(", ");
    }
    return output.ToString();
}
公共静态字符串SummaryMethodCall(MethodBase方法,参数对象[]值)
{
var输出=新的StringBuilder(方法名+“已调用:”);
ParameterInfo[]parameters=method.GetParameters();
对于(int i=0;i=值。长度?“:值[i]
);
如果(i<参数长度-1)
输出。追加(“,”);
}
返回output.ToString();
}

您可以像这样获取方法名称和参数

try
{
    int a = 0;
    int i = 1 / a;
}
catch (Exception exception)
{
    StackTrace s = new StackTrace(exception);
    StackFrame stackFrame = s.GetFrame(s.FrameCount - 1);
    if (stackFrame != null)
    {
        StringBuilder stackBuilder = new StringBuilder();
        MethodBase method = stackFrame.GetMethod();
        stackBuilder.AppendFormat("Method Name = {0}{1}Parameters:{1}", method.Name, Environment.NewLine);

        foreach (ParameterInfo parameter in method.GetParameters())
        {
            stackBuilder.AppendFormat("{0} {1}", parameter.ParameterType.FullName, parameter.Name);
            stackBuilder.AppendLine();
        }

        // or use this to get the value
        //stackBuilder.AppendLine("param1  = " + param1);
        //stackBuilder.AppendLine("param2  = " + param2);
    }
}

我不确定您是否可以像调试器一样直接从堆栈中获取参数值。

公认的答案和所描述的许多解决方案都可以很好地工作,但您所做的是根据方法签名中的参数,在源代码中添加一个稍有不同的代码块

当需要添加新参数时,您需要记住更新处理程序以添加新参数。或者,如果删除一个参数,则需要记住从异常处理程序中删除该参数

如果您有两个或更多的
try..catch
块,该怎么办?然后,您现在有两个代码块要保持最新。绝对不是对重构友好的

另一种方法是使用名为的技术删除日志代码

一个这样的工具,以促进这是一个产品称为

使用PostSharp,您可以编写一个记录器,而不需要混乱的方法和特定于参数的代码,只要抛出异常就可以调用它。例如(使用PostSharp的1.5版):

LoggerAttribute.cs-

任何在
MyMethod
中引发异常的操作都将导致执行
OnException
方法

PostSharp有两个版本。1.5版是GPL下的免费开源版本,面向.NET 2.0。PostSharp 2.0并非完全免费,但其社区版将支持上述基本功能。

来自加密模糊器的功能可以满足您的需要

异常报告包括所有相关信息,包括完整堆栈跟踪信息、所有方法参数和局部变量的值,以及系统信息、异常时间、版本号和可选的开发人员定义的自定义数据,如日志文件、屏幕截图等


免责声明:我为LogicNP软件工作,该软件是加密模糊器的开发人员。

导致异常的最后一个调用方法已经是堆栈跟踪的一部分。。。你的问题我遗漏了什么吗?@tejs-他也想要传递给方法的参数值。请看这里:我喜欢这种方法。我总是惊讶地发现数据属性很少被使用……哇,我从来没有听说过这个特性一个警告,克里斯蒂安。“不丢失堆栈跟踪”并非100%准确。当您重新抛出异常时,即使使用
throw,则该代码块中的堆栈跟踪位置将重置。因此,如果您正在分发PDB文件以获取堆栈跟踪中的行号,则如果您重试,某些行号将被禁用。该属性提供存储异常详细信息的功能。当系统异常提供必要的实现时,我认为不需要自定义异常。调用记录器(
MyLogger.Log(exceptionInstance)
)就足够了。
[Serializable]
public class LoggerAttribute : OnExceptionAspect
{
  public override void OnException(MethodExecutionEventArgs eventArgs)
  {
    Console.WriteLine(eventArgs.Method.DeclaringType.Name);
    Console.WriteLine(eventArgs.Method.Name);
    Console.WriteLine(eventArgs.Exception.StackTrace);

    ParameterInfo[] parameterInfos = eventArgs.Method.GetParameters();
    object[] paramValues = eventArgs.GetReadOnlyArgumentArray();

    for (int i = 0; i < parameterInfos.Length; i++)
    {
      Console.WriteLine(parameterInfos[i].Name + "=" + paramValues[i]);
    }

    eventArgs.FlowBehavior = FlowBehavior.Default;
  }
}
[Logger]
public class MyClass
{
  public void MyMethod(int x, string name)
  {
      // Something that throws an exception
  }
}