减少C#中的使用数量

4

我的问题可能很愚蠢,或者根本不是问题,但我还是要问一下...

在我的ASP.net MVC项目中,我执行了相当多的数据库操作,每次都创建两个对象,分别是SqlConnectionSqlCommand

我在下面展示了一个例子。

using (SqlConnection connection = new SqlConnection(connectionString))
{
  using (SqlCommand command = new SqlCommand("sRegisterUser", connection))
  {

我在一个类的不同方法中执行各种不同的操作。

我的问题是如何减少每次创建这些对象?如何全局创建它们?

PS:sRegisterUser是一个存储过程,其他方法使用不同的过程,并将不同的值作为参数传递。

请帮忙解决一下,先谢谢了。


嗯...你应该每次创建和处理它们。你可以尝试将创建移动到一个公共方法中(以某种方式),但你仍然应该创建和处理连接和命令。 - Patryk Ćwiek
听起来你需要使用仓储模式来开始分离实际的业务逻辑和数据访问。 - Yahya
你能否给我更详细地解释一下仓储模式? - RandomUser
3个回答

11

答案是不要。你不想分享这些对象,因为你正在恰当地使用它们。


1
@RandomUser,这些类是为了像这样使用而构建的。创建一个new SqlConnection并不意味着类似地创建一个新管道到SQL Server。此外,它们中有未受管理的资源,这就是为什么它们实现了IDisposable,这些资源需要清理。任何实现IDisposable的东西都是为了被创建、使用和处理;每一次 - Mike Perrenoud
3
打开数据库连接会占用资源,如果您没有必要持有这些资源,就不应该保留它们。using 块的作用是释放(dispose)这些资源。在 using 块的末尾,会调用 dispose 方法来释放这些资源。 - CSharper
谢谢大家,这很有帮助。 - RandomUser
@eFloh:这是可以做到的。但我通常不建议这样做,因为a)现在你需要自己处理disposing,所以你必须绝对加强该类,并且b)在我看来没有真正的好处。为了一个单独的“using”语句而增加这样的开销通常会引起问题。 - Mike Perrenoud
@MichaelPerrenoud 我已经使用了数据库上下文模式五年了,到目前为止它一直是一个巨大的帮助。代码更加简洁,更易于阅读和编写,数据辅助方法需要的参数更少,遗漏未释放对象的风险接近于零,还提供了友好的抽象层来处理事务。核心与几乎所有 ADO.NET 提供程序兼容,并可以扩展以更好地适应特定提供程序的特定需求和功能。我绝对推荐这种方法。 - Crono
显示剩余4条评论

3
你不需要这么做。你要么让该对象一直存在,这是不好的。要么按照应该且目前的方法来处理它。
那么,为什么要使用using
因为在 Windows 中,使用using是必要的以便能够正确地释放句柄。
你也可以像使用using一样编写以下代码:
SqlConnection connection = new SqlConnection(connectionString);
connection.Close();
connection.Dispose();

using语句在代码抛出错误时也会自动释放资源。使用using语句实际上是编写此代码的最简短方式。

因此,安全处理错误的版本应该如下:

SqlConnection connection;

try
{
    connection = new SqlConnection(connectionString);

    ...

    connection.Close();
}
finally
{
    connection.Dispose();
}

为了让它真正类似于“使用”,您需要在finally块中放置Close()Dispose()调用。 - Sven Grosen
@ledbutter:谢谢。我以这种方式发布它是为了清楚地展示错误处理问题。已经调整了带有错误保存版本的答案。 - Patrick Hofman

1
正如其他人已经说过的那样,你现在所做的一切都是没有问题的。ADO.NET对象是用来使用和处理的。作为一个经验法则,你应该尽可能晚地创建它们尽快释放它们

话虽如此,我理解你在这里所努力的,并且我有一些想法,你可能会对保持良好编程实践并使生活更轻松感兴趣。

如果您想使代码更简洁,可以链接using语句:

using (var cn = new SqlConnection(yourConnectionString))
using (var cmd = new SqlCommand(yourQuery, cn))
{
    // do stuff
}

IDE不会尝试缩进第二个块,这样可以更轻松地阅读。
您还可以为过程创建一个抽象层
public static class Procedures
{
    public static void RegisterUser() // add whatever parameters you need
    {
        using (var cn = new SqlConnection(yourConnectionString))
        using (var cmd = new SqlCommand(yourQuery, cn))
        {
            // do stuff
        }
    }
}

从那时起,您可以通过调用以下方式来执行您的程序:

Procedures.RegisterUser();

另一种选择是引入工厂模式来获取您的对象。这样做不会减少它们的数量,但可能有助于使它们全部设置好(即正确的连接字符串)。
您还可以创造性地结合这两种模式。实现IDisposable的自定义类可以负责创建必要的ADO对象、打开连接、执行查询、关闭连接并在其自身被处理时处置任何需要处置的对象。
随意选择。

链式调用是否与我所使用的类似?抱歉我有些愚蠢。 - RandomUser
@RandomUser,完全相同,只是它将会是一个块而不是两个。这样写、缩进和最终阅读可能更容易些。 - Crono
@RandomUser:实际上,你可以删除括号,因为第一个“using”中只有一个语句。 - Patrick Hofman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接