gpt4 book ai didi

c# - 我应该如何防御性地编程?

转载 作者:IT王子 更新时间:2023-10-29 03:59:58 25 4
gpt4 key购买 nike

关闭。这个问题是opinion-based .它目前不接受答案。












想改善这个问题吗?更新问题,以便可以通过 editing this post 用事实和引文回答问题.

2年前关闭。




Improve this question




我正在使用一个用于创建数据库连接的小例程:


public DbConnection GetConnection(String connectionName)
{
ConnectionStringSettings cs= ConfigurationManager.ConnectionStrings[connectionName];
DbProviderFactory factory = DbProviderFactories.GetFactory(cs.ProviderName);
DbConnection conn = factory.CreateConnection();
conn.ConnectionString = cs.ConnectionString;
conn.Open();

return conn;
}

然后我开始查看 .NET 框架文档,看看 记录在案 各种事情的行为都是,看看我是否可以处理它们。

例如:
ConfigurationManager.ConnectionStrings...

documentation说打电话 连接字符串 抛出 ConfigurationErrorException如果它无法检索集合。在这种情况下,我无能为力来处理这个异常,所以我会放手。

下一部分是 的实际索引连接字符串 找到连接名称:
...ConnectionStrings[connectionName];

在这种情况下, ConnectionStrings documentation说该属性将返回 如果找不到连接名称。我可以检查是否发生这种情况,并抛出一个异常,让高人知道他们给出了无效的 connectionName:
ConnectionStringSettings cs= 
ConfigurationManager.ConnectionStrings[connectionName];
if (cs == null)
throw new ArgumentException("Could not find connection string \""+connectionName+"\"");

我重复同样的练习:
DbProviderFactory factory = 
DbProviderFactories.GetFactory(cs.ProviderName);

GetFactory方法没有关于如果指定 ProviderName 的工厂会发生什么的文档。找不到。没有记录返回 null ,但我仍然可以防御,而且 检查 为空:
DbProviderFactory factory = 
DbProviderFactories.GetFactory(cs.ProviderName);
if (factory == null)
throw new Exception("Could not obtain factory for provider \""+cs.ProviderName+"\"");

接下来是构建 DbConnection 对象:
DbConnection conn = factory.CreateConnection()

又是 documentation没有说明如果无法创建连接会发生什么,但我可以再次检查 null 返回对象:
DbConnection conn = factory.CreateConnection()
if (conn == null)
throw new Exception.Create("Connection factory did not return a connection object");

接下来是设置 Connection 对象的属性:
conn.ConnectionString = cs.ConnectionString;

文档没有说明如果无法设置连接字符串会发生什么。它会抛出异常吗?它会忽略它吗?与大多数异常(exception)情况一样,如果在尝试设置连接的 ConnectionString 时出现错误,我将无法从中恢复。所以我什么都不做。

最后,打开数据库连接:
conn.Open();

Open method DbConnection 是抽象的,因此由 DbConnection 的任何提供者决定它们抛出什么异常。抽象的开放方法文档中也没有关于如果出现错误我可以预期会发生什么的指导。如果连接出现错误,我知道我无法处理它 - 我将不得不让它冒泡,调用者可以向用户显示一些 UI,然后让他们再试一次。


public DbConnection GetConnection(String connectionName)
{
//Get the connection string info from web.config
ConnectionStringSettings cs= ConfigurationManager.ConnectionStrings[connectionName];

//documented to return null if it couldn't be found
if (cs == null)
throw new ArgumentException("Could not find connection string \""+connectionName+"\"");

//Get the factory for the given provider (e.g. "System.Data.SqlClient")
DbProviderFactory factory = DbProviderFactories.GetFactory(cs.ProviderName);

//Undefined behaviour if GetFactory couldn't find a provider.
//Defensive test for null factory anyway
if (factory == null)
throw new Exception("Could not obtain factory for provider \""+cs.ProviderName+"\"");

//Have the factory give us the right connection object
DbConnection conn = factory.CreateConnection();

//Undefined behaviour if CreateConnection failed
//Defensive test for null connection anyway
if (conn == null)
throw new Exception("Could not obtain connection from factory");

//Knowing the connection string, open the connection
conn.ConnectionString = cs.ConnectionString;
conn.Open()

return conn;
}

概括

所以我的四行函数变成了 12 行,并且需要 5 分钟的文档查找。最后,我确实发现了一种允许方法返回 null 的情况。但实际上,我所做的只是将访问冲突异常(如果我尝试在空引用上调用方法)转换为 InvalidArgumentException .

我还发现了两种可能的情况,其中可能存在 返回对象;但同样,我只用一个异常(exception)换了另一个。

从积极的方面来说,它确实发现了两个问题,并解释了异常消息中发生的事情,而不是在路上发生的坏事(即降压到此为止)

但是这值得吗?这是矫枉过正吗?这个防御性编程出错了吗?

最佳答案

手动检查配置并抛出异常并不比在缺少配置时让框架抛出异常更好。无论如何,您只是在重复发生在框架方法内部的前提条件检查,这会使您编写冗长的代码而没有任何好处。 (实际上,您可能通过将所有内容作为基础 Exception 类抛出来删除信息。框架抛出的异常通常更具体。)

编辑:这个答案似乎有些争议,所以要详细说明一下:防御性编程意味着“为意外做好准备”(或“偏执”),其中一种方法是进行大量前提条件检查。在许多情况下,这是一种很好的做法,但是与所有做法一样,应该权衡成本与 yield 。

例如,抛出“无法从工厂获得连接”异常并没有提供任何好处,因为它没有说明为什么无法获得提供者 - 并且下一行无论如何都会抛出异常,如果提供者为空。因此,前提条件检查的成本(在开发时间和代码复杂性方面)是不合理的。

另一方面,验证连接字符串配置是否存在的检查可能是合理的,因为异常可以帮助告诉开发人员如何解决问题。无论如何,您将在下一行中获得的空异常不会告诉缺少的连接字符串的名称,因此您的前提条件检查确实提供了一些值。例如,如果您的代码是组件的一部分,则该值非常大,因为组件的用户可能不知道该组件需要哪些配置。

对防御性编程的另一种解释是,您不仅应该检测错误情况,还应该尝试从可能发生的任何错误或异常中恢复。我不相信这是一个好主意。

基本上你应该只处理你可以做些什么的异常。无论如何都无法恢复的异常,应该向上传递给顶级处理程序。在 Web 应用程序中,顶级处理程序可能只显示一个通用错误页面。但是在大多数情况下,如果数据库离线或缺少某些关键配置,则没有太多可做的事情。

这种防御性编程有意义的某些情况是,如果您接受用户输入,并且该输入可能导致错误。例如,如果用户提供一个 URL 作为输入,并且应用程序尝试从该 URL 获取某些内容,那么检查 URL 是否正确并处理可能由请求导致的任何异常就非常重要。这允许您向用户提供有值(value)的反馈。

关于c# - 我应该如何防御性地编程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1053215/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com