我知道这听起来很奇怪,但是我需要在每个方法中放置一个包装try catch块来捕获所有异常。我们有数千种方法,我需要以自动方式完成。你有什么建议?
我打算解析所有cs文件并检测方法,并在应用程序中插入try catch块。你能告诉我任何我可以轻松使用的解析器吗?或任何有助于我的事情......
每个方法都有其唯一的数字,如5006
public static LogEntry Authenticate(....)
{
LogEntry logEntry = null;
try
{
....
return logEntry;
}
catch (CompanyException)
{
throw;
}
catch (Exception ex)
{
logEntry = new LogEntry(
"5006",
RC.GetString("5006"), EventLogEntryType.Error,
LogEntryCategory.Foo);
throw new CompanyException(logEntry, ex);
}
}
我为此创造了这个; http://thinkoutofthenet.com/index.php/2009/01/12/batch-code-method-manipulation/
答案 0 :(得分:40)
不要做。口袋妖怪(“必须全部捕获”)错误处理没有充分的理由。
编辑:几年后,需要进行细微修改。我会说“至少不要手动做”。使用AOP工具或Weaver(如PostSharp或Fody)将其应用于最终结果代码,但请务必考虑其他有用的跟踪或诊断数据点,如捕获执行时间,输入参数,输出参数等。
答案 1 :(得分:12)
如果你必须这样做,那么你必须这样做。但是,您可能会尝试与强迫您使用UnhandledException event of the AppDomain class的人进行交谈。在向用户报告之前,它会向您提供有关任何方法中每个未捕获异常的通知。由于您还可以从异常对象获取堆栈跟踪,因此您将能够准确地确定每个异常发生的位置。这比使用异常处理程序装配代码要好得多。
话虽如此,如果我有来做,我会使用一些正则表达式来识别每个方法的开始和结束,并使用它来在任何地方插入一些异常处理程序。为这种情况编写正则表达式的技巧将是在MSDN文档here中更多地解释平衡组定义。还有一个使用平衡组here的相关示例。
答案 2 :(得分:3)
也许谁提出这个要求并不明白你仍然可以捕获所有异常(在顶部)而不在每个函数中都放置try-catch。您可以看到如何catch all unhandled exceptions here的示例。我认为这是一个更好的解决方案,因为你实际上可以做一些异常,并报告它,而不是盲目地掩盖所有异常,导致极难追踪错误。
这类似于Scott的解决方案,但也为Application.ThreadException异常添加了一个事件处理程序,如果您使用的是线程,则会发生这种情况。可能最好同时使用它们以捕获所有异常。
答案 3 :(得分:3)
请参阅我的回答here,其中描述了如果您使用“全部捕获所有”异常处理,您将被迫忍受的一些性能权衡。
正如斯科特所说,做同样事情的最好方法是UnhandledException事件。我想杰夫实际上是在早期的SO播客中讨论过这个问题。
答案 4 :(得分:2)
我和StingyJack在一起,不要这样做!
然而,如果神在高级法令上必须要做,那么请看answer这个问题Get a method’s contents from a cs file
答案 5 :(得分:2)
首先,我和StingyJack和Binary Worrier在一起。有一个很好的理由,默认情况下不会捕获异常。如果你真的想要捕获异常并且稍微好一些,你可以在Application.Run()
调用周围放置一个try-catch块并从那里开始工作。
当处理外部来源(文件,互联网等)时,应该(通常)捕获某些异常(连接错误,丢失文件,等等)。然而,在我的书中,其他地方的例外意味着:1)错误,2)有缺陷的逻辑,或者3)数据验证不良......
总之,完全没有回答你的问题,你确定你想要这样做吗?
答案 6 :(得分:1)
我想写这个作为所有答案的答案然后你可以通过问题RSS知道; 要求来自我们的技术领导者: 这是他的理由: 我们不需要找出哪个func在生产代码中有问题,任何问题都被报告为警报,我们将一个唯一的代码放到ecery catch块中,我们看到问题出在哪里。他知道有一个全局错误处理,但在这种情况下没有帮助,并且stacktrace在发布模式下不合适,所以他需要一个try catch块,如下所示:
everyMethod(...){
try
{
..
catch(Exception e)
{
RaiseAlert(e.Message.. blabla)
}
}
答案 7 :(得分:1)
所以这里有一个想知道的例子; 5006是这种方法独有的;
public static LogEntry Authenticate(....)
{
LogEntry logEntry = null;
try
{
....
return logEntry;
}
catch (CompanyException)
{
throw;
}
catch (Exception ex)
{
logEntry = new LogEntry(
"5006",
RC.GetString("5006"), EventLogEntryType.Error,
LogEntryCategory.Foo);
throw new CompanyException(logEntry, ex);
}
}
答案 8 :(得分:1)
如果在每个方法中都放置了一个RaiseAlert调用,那么假设您重用方法,那么您收到的错误堆栈将会非常混乱,如果不是不准确的话。记录方法实际上只需要在事件或最顶层的方法中调用。如果有人提出异常处理需要在每个方法中的问题,他们就不会理解异常处理。
几年前,我们实施了一种做法,即必须在每个事件中进行异常处理,并且一位开发人员将其视为“每种方法”。当它们完成后,我们有几个星期值得撤消,因为没有任何异常报告是可以重现的。 我假设他们比你知道的更好,但从未质疑他们解释的有效性。
实现AppDomain.UnhandledException是一个很好的备份,但是你在该方法中唯一的办法是在记录异常后终止应用程序。您必须编写一个全局异常处理程序来防止这种情况。
答案 9 :(得分:1)
我必须做一些类似的事情(在很多行代码中添加一些东西);我用了正则表达式。
我会创建一个正则表达式脚本,找到每个函数的开头并在开始后插入try catch块。然后我会创建另一个正则表达式脚本来查找函数的结尾(通过在它之后找到函数的开头)并在结尾处插入try catch块。这不会让你100%的方式,但它可能达到80%,这有望足够接近你可以做边缘情况而不需要太多的工作。
答案 10 :(得分:0)
如果您真的必须这样做,为什么要在修改源代码时遇到麻烦,何时可以直接修改已编译的可执行文件/库
看看Cecil(参见website),它是一个允许你直接修改字节码的库,使用这种方法,你的整个问题可以在几百行C#代码中解决。< / p>
答案 11 :(得分:0)
由于您在此处发布了一个问题,我相信这是您必须要做的事情之一。因此,为什么不做Scott建议的并使用AppDomain事件处理程序,而不是猛烈地对抗不屈的墙。您可以满足要求,而无需花费数小时的优质计费时间进行繁重的工作。我相信一旦你告诉你的老板有多少测试更新每个文件都需要,使用事件处理程序将是一个明智的选择!
答案 12 :(得分:0)
所以你真的不想在每个函数中放置相同的try-catch块,对吧?您将不得不为每个函数定制每个try-catch。哇!似乎是“简化”调试的一个很长的路。
如果用户在生产中报告错误,为什么不能启动Visual Studio并重现步骤和调试?
答案 13 :(得分:0)
如果您必须将try / catch块添加到每个方法并且scott的答案(AppDomain.UnhandledException)是不够的,您还可以查看拦截器。我相信Castle项目有很好的方法拦截器实现。
答案 14 :(得分:0)
我猜你可以使用面向方面的编程,我想亲自动手。例如http://www.postsharp.org/aopnet/overview
虽然这种要求确实是邪恶的。
答案 15 :(得分:0)
如果你真的必须这样做,每次包装异常的另一种方法是使用Exception.Data捕获附加信息,然后重新抛出原始异常 ......
catch (Exception ex)
{
logEntry = new LogEntry("5006",
RC.GetString("5006"), EventLogEntryType.Error,
LogEntryCategory.Foo);
ex.Data.Add("5006",logEntry);
throw;
}
现在在顶级,您可以转储ex.Data的内容以获取您可能想要的所有其他信息。这允许您在.Data集合中放置文件名,用户,...以及各种其他有用信息,以帮助理解发生异常的原因。
答案 16 :(得分:0)
我做了一些研究工作,需要在大约2年前解析C#代码,并发现SharpDevelop项目的源代码非常好。如果您从源代码库中解压缩SharpDevParser项目(这是两年前,不确定项目名称是否保持不变),那么您可以像这样使用解析器对象:
CSharpBinding.Parser.TParser = new CSharpBinding.Parser.TParser();
SIP.ICompilationUnitBase unitBase = sharpParser.Parse(fileName);
这为您提供了compUnit.Classes,您可以遍历每个类并在其中查找方法。
答案 17 :(得分:0)
我正在帮他的朋友在他写的C#XNA游戏中发现内存泄漏。 我建议我们尝试检查每个方法被调用的次数。 为了保持计数,我编写了一个python脚本,添加了两行来更新带有详细信息的Dictionary。
基本上我写了一个python脚本来修改一些带有2行所需的400~方法。 这段代码可以帮助别人做更多事情,比如OP想要的奇怪事情。
代码使用第3行配置的路径,并在处理.cs文件时递归迭代。它也有子目录。
当找到cs文件时,它会查找方法声明,它会尽量小心。备份 - 如果我的脚本违反你的代码,我没有责任!
import os, re
path="D:/Downloads/Dropbox/My Dropbox/EitamTool/NetworkSharedObjectModel"
files = []
def processDir(path, files):
dirList=os.listdir(path)
for fname in dirList:
newPath = os.path.normpath(path + os.sep + fname)
if os.path.isdir(newPath):
processDir(newPath, files)
else:
if not newPath in files:
files.append(newPath)
newFile = handleFile(newPath)
if newPath.endswith(".cs"):
writeFile(newPath, newFile)
def writeFile(path, newFile):
f = open(path, 'w')
f.writelines(newFile)
f.close()
def handleFile(path):
out = []
if path.endswith(".cs"):
f = open(path, 'r')
data = f.readlines()
f.close()
inMethod = False
methodName = ""
namespace = "NotFound"
lookingForMethodDeclerationEnd = False
for line in data:
out.append(line)
if lookingForMethodDeclerationEnd:
strippedLine = line.strip()
if strippedLine.find(")"):
lookingForMethodDeclerationEnd = False
if line.find("namespace") > -1:
namespace = line.split(" ")[1][0:-2]
if not inMethod:
strippedLine = line.strip()
if isMethod(strippedLine):
inMethod = True
if strippedLine.find(")") == -1:
lookingForMethodDeclerationEnd = True
previousLine = line
else:
strippedLine = line.strip()
if strippedLine == "{":
methodName = getMethodName(previousLine)
out.append(' if (!MethodAccess.MethodAccess.Counter.ContainsKey("' + namespace + '.' + methodName + '")) {MethodAccess.MethodAccess.Counter.Add("' + namespace + '.' + methodName + '", 0);}')
out.append("\n" + getCodeToInsert(namespace + "." + methodName))
inMethod = False
return out
def getMethodName(line):
line = line.strip()
lines = line.split(" ")
for littleLine in lines:
index = littleLine.find("(")
if index > -1:
return littleLine[0:index]
def getCodeToInsert(methodName):
retVal = " MethodAccess.MethodAccess.Counter[\"" + methodName + "\"]++;\n"
return retVal
def isMethod(line):
if line.find("=") > -1 or line.find(";") > -1 or line.find(" class ") > -1:
return False
if not (line.find("(") > -1):
return False
if line.find("{ }") > -1:
return False
goOn = False
if line.startswith("private "):
line = line[8:]
goOn = True
if line.startswith("public "):
line = line[7:]
goOn = True
if goOn:
return True
return False
processDir(path, files)