【发布时间】:2025-12-22 17:30:17
【问题描述】:
我正在努力提高处理异常的能力,但是当我尽力捕捉它们时,我觉得我的代码变得非常丑陋、不可读和混乱。我很想看看其他人如何通过给出一个实际的例子和比较解决方案来解决这个问题。
我的示例方法从 URL 下载数据并尝试将其序列化为给定类型,然后返回填充数据的实例。
首先,完全没有任何异常处理:
private static T LoadAndSerialize<T>(string url)
{
var uri = new Uri(url);
var request = WebRequest.Create(uri);
var response = request.GetResponse();
var stream = response.GetResponseStream();
var result = Activator.CreateInstance<T>();
var serializer = new DataContractJsonSerializer(result.GetType());
return (T)serializer.ReadObject(stream);
}
我觉得这样的方法可读性很强。我知道该方法中有一些不必要的步骤(例如 WebRequest.Create() 可以接受一个字符串,并且我可以在不给它们变量的情况下链接方法)但是我会这样保留它以便更好地与有异常的版本进行比较-处理。
这是处理所有可能出错的第一次尝试:
private static T LoadAndSerialize<T>(string url)
{
Uri uri;
WebRequest request;
WebResponse response;
Stream stream;
T instance;
DataContractJsonSerializer serializer;
try
{
uri = new Uri(url);
}
catch (Exception e)
{
throw new Exception("LoadAndSerialize : Parameter 'url' is malformed or missing.", e);
}
try
{
request = WebRequest.Create(uri);
}
catch (Exception e)
{
throw new Exception("LoadAndSerialize : Unable to create WebRequest.", e);
}
try
{
response = request.GetResponse();
}
catch (Exception e)
{
throw new Exception(string.Format("LoadAndSerialize : Error while getting response from host '{0}'.", uri.Host), e);
}
if (response == null) throw new Exception(string.Format("LoadAndSerialize : No response from host '{0}'.", uri.Host));
try
{
stream = response.GetResponseStream();
}
catch (Exception e)
{
throw new Exception("LoadAndSerialize : Unable to get stream from response.", e);
}
if (stream == null) throw new Exception("LoadAndSerialize : Unable to get a stream from response.");
try
{
instance = Activator.CreateInstance<T>();
}
catch (Exception e)
{
throw new Exception(string.Format("LoadAndSerialize : Unable to create and instance of '{0}' (no parameterless constructor?).", typeof(T).Name), e);
}
try
{
serializer = new DataContractJsonSerializer(instance.GetType());
}
catch (Exception e)
{
throw new Exception(string.Format("LoadAndSerialize : Unable to create serializer for '{0}' (databinding issues?).", typeof(T).Name), e);
}
try
{
instance = (T)serializer.ReadObject(stream);
}
catch (Exception e)
{
throw new Exception(string.Format("LoadAndSerialize : Unable to serialize stream into '{0}'.", typeof(T).Name), e);
}
return instance;
}
这里的问题是,虽然所有可能出错的东西都会被捕获并给出一个有意义的例外,但这是一个相当大比例的混乱。
那么,如果我改为链式捕获会怎样。我的下一个尝试是这样的:
private static T LoadAndSerialize<T>(string url)
{
try
{
var uri = new Uri(url);
var request = WebRequest.Create(uri);
var response = request.GetResponse();
var stream = response.GetResponseStream();
var serializer = new DataContractJsonSerializer(typeof(T));
return (T)serializer.ReadObject(stream);
}
catch (ArgumentNullException e)
{
throw new Exception("LoadAndSerialize : Parameter 'url' cannot be null.", e);
}
catch (UriFormatException e)
{
throw new Exception("LoadAndSerialize : Parameter 'url' is malformed.", e);
}
catch (NotSupportedException e)
{
throw new Exception("LoadAndSerialize : Unable to create WebRequest or get response stream, operation not supported.", e);
}
catch (System.Security.SecurityException e)
{
throw new Exception("LoadAndSerialize : Unable to create WebRequest, operation was prohibited.", e);
}
catch (NotImplementedException e)
{
throw new Exception("LoadAndSerialize : Unable to get response from WebRequest, method not implemented?!.", e);
}
catch(NullReferenceException e)
{
throw new Exception("LoadAndSerialize : Response or stream was empty.", e);
}
}
虽然看起来确实更容易,但我在这里非常倾向于智能感知,以提供所有可能从方法或类中抛出的异常。我不相信这个文档是 100% 准确的,如果某些方法来自 .net 框架之外的程序集,我会更加怀疑。例如,DataContractJsonSerializer 在智能感知上没有显示异常。这是否意味着构造函数永远不会失败?我可以确定吗?
与此相关的其他问题是某些方法会抛出相同的异常,这使得错误更难描述(这个或这个或这个出错),因此对用户/调试器的用处不大。
第三种选择是忽略所有异常,除了那些允许我采取诸如重试连接之类的操作的异常。如果 url 为 null,则 url 为 null,捕获它的唯一好处是更详细的错误消息。
我很想看看你的想法和/或实现!
【问题讨论】:
-
出于这个原因,我经常渴望一种类似于 case 语句的直通功能来捕获异常。
-
通过用自己的异常包装异常来增加什么价值?简单地不捕捉这些异常并让它们冒泡解开有什么问题?您真的需要进一步解释
UriFormatException是与 Uri 相关的异常吗?这不是已经很明显了吗? -
@Siege - 你的意思是“失败”。
-
仅 捕获您的代码可以 100% 处理的异常 - 只有一个容易理解的原因。否则,您所做的只是 a) 添加噪音,或 b) 隐藏异常。
-
我认为您的方法中有太多代码。你可以拆分它。
标签: c# exception-handling