5

这是我为 C# 控制台应用程序提出的(非常简化以说明问题空间)设计。数据库连接实现 IDisposable,并且此解决方案不允许using数据库连接对象。有人可以为控制台应用程序提出更正确的结构吗?这是我需要经常解决的问题。

class Program 
{
    SQLiteConnection sourceConnection;
    SQLiteConnection destinationConnection;

    static void Main(string[] args)
    {
        Program shell = new Program();

        // get connection strings from command line arguments
        string sourceConnectionString = shell.getConnectionString(args);
        string destinationConnectionString = shell.getConnectionString(args);

        // call non-static methods that use
        shell.setUpConnections(sourceConnectionString, destinationConnectionString);

        shell.doDatabaseWork();
    }

    private void setUpConnections(string sourceConnectionString, string destinationConnectionString)
    {
        sourceConnection = new SQLiteConnection(sourceConnectionString);
        destinationConnection = new SQLiteConnection(destinationConnectionString);
    }

    private void doDatabaseWork()
    {
        // use the connections here
    }
}

编辑:

有些人不明白为什么我希望它们作为成员变量。这是我在 doDatabaseWork 中的用例(有点伪编码):

foreach (Row sourceRow in DBResultSet)
{
  string sourceXml = sourceRow.Columns["MyColumnName"].Value;
  string destinationXML = transformUsingXSLT(sourceXml);
  writeToDestination(destinationXml);
}

看看我想如何在这个循环的生命周期内保持这些连接打开?

4

5 回答 5

6

如何编写一个实现 IDisposable 的类。

在您的类构造函数中,您可以实例化您的数据库连接。

然后在 IDisposable.Dispose 方法中,编写用于关闭数据库连接的拆卸代码。

这是一个代码示例来演示我的意思:

public class DBWrapper : IDisposable
{
    public SqlConnection Connection1 { get; set; }
    public SqlConnection Connection2 { get; set; }

    public DBWrapper()
    {
        Connection1 = new SqlConnection();
        Connection1.Open();
        Connection2 = new SqlConnection();
        Connection2.Open();
    }
    public void DoWork()
    {
        // Make your DB Calls here
    }

    public void Dispose()
    {
        if (Connection1 != null)
        {
            Connection1.Dispose();
        }
        if (Connection2 != null)
        {
            Connection2.Dispose();
        }
    }
}

然后,从 Program 类的 main 方法中:

class Program
{
    static void Main(string[] args)
    {
        using (DBWrapper wrapper = new DBWrapper())
        {
            wrapper.DoWork();
        }
    }
}
于 2009-05-06T03:23:58.800 回答
2

斯科特的回答是一种方法。您也可以考虑使用 try{} finally 代替?

static void Main(string[] args)
{
    Program shell = new Program();

    // get connection strings from command line arguments
    string sourceConnectionString = shell.getConnectionString(args);
    string destinationConnectionString = shell.getConnectionString(args);

    // call non-static methods that use
    shell.setUpConnections(sourceConnectionString, destinationConnectionString);
    try
    {
      shell.doDatabaseWork();
    }
    finally
    {
      if(sourceConnection != null)
        sourceConnection.Dispose();
      if(destinationConnection != null)
        destinationConnection.Dispose();
    }
}
于 2009-05-06T03:25:42.027 回答
2

就个人而言,我认为你想多了,这个线程中的代码示例过于复杂恕我直言。我不知道为什么人们在他们的 Program 类上实现 IDisposable ,因为它在退出时被释放。

我想不出一个不使用或为什么不能使用 using(){} 语句的原因。

你想打开一个连接并保持它吗?为什么?所有真正的连接都在 .net 连接池的幕后,所以新建 Connection 对象没什么大不了的。只需根据需要打开和关闭它们,连接池在幕后处理所有这些。

我编辑了我的示例以将其包装在一个类中,以便您也可以进行封装。

class Program 
{
    static void Main(string[] args)
    {
        DBWorker worker = new DBWorker();
        worker.DoDatabaseWork();
    }
}

public class DBWorker 
{

    private void DoDatabaseWork()
    {
        using (SQLiteConnection sourceDB = new SQLiteConnection( GetConnectionString() ))
        {
            sourceDB.Open();
            using (SQLiteConnection destDB = new SQLiteConnection( GetConnectionString() ))
            {
                destDB.Open();
            }
        }
    }

}
于 2009-05-06T04:21:35.980 回答
2

我认为最好的解决方案是从 Program 类中提取主要逻辑。Program 类是主要工作的某种启动器。并且为 SqlConnections 提供包装器确实不是一个好主意,因为它们已经是托管资源,包装它们是多余的。因此我的解决方案如下所示:

class ProgramCore : IDisposable
{
    internal ProgramCore(string sourceConnectionString, string destinationConnectionString)
    {
        setUpConnections(sourceConnectionString, destinationConnectionString);
    }

    internal void Execute()
    {
        // do whatever you want
        doDatabaseWork();
        // do whatever you want
    }

    public void Dispose()
    {
        if (_sourceConnection != null)
            _sourceConnection.Dispose();
        if (_destinationConnection != null)
            _destinationConnection.Dispose();
    }

    private void setUpConnections(string sourceConnectionString, string destinationConnectionString)
    {
        _sourceConnection = new SQLiteConnection(sourceConnectionString);
        _destinationConnection = new SQLiteConnection(destinationConnectionString);
    }

    private void doDatabaseWork()
    {
        // use the connections here
    }

    private SQLiteConnection _sourceConnection;
    private SQLiteConnection _destinationConnection;
}

class Program
{
    static void Main(string[] args)
    {
        // get connection strings from command line arguments
        string sourceConnectionString = GetConnectionString(args);
        string destinationConnectionString = GetConnectionString(args);

        using (ProgramCore core = new ProgramCore(sourceConnectionString, destinationConnectionString))
        {
            core.Execute();
        }
    }

    static string GetConnectionString(string[] args)
    {
        // provide parsing here
    }
}
于 2009-05-06T04:42:38.753 回答
0

嗯,我看没有人提到过这样做。您不必拥有在using本地声明中使用的变量。


class Program 
{
    SQLiteConnection sourceConnection;
    SQLiteConnection destinationConnection;

    static void Main(string[] args)
    {
        Program shell = new Program();

        // get connection strings from command line arguments
        string sourceConnectionString = shell.getConnectionString(args);
        string destinationConnectionString = shell.getConnectionString(args);

        using (sourceConnection = new SQLiteConnection(sourceConnectionString))
        using (destinationConnection = new SQLiteConnection(destinationConnectionString))
        {
            shell.doDatabaseWork();
        }
    }

    private void doDatabaseWork()
    {
        // use the connections here
    }
}
于 2009-05-07T21:51:01.720 回答