[英]How do I structure a C# console application to efficiently use IDisposable database resources?
這是我為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);
}
看看我想如何在這個循環的生命周期中保持這些連接打開?
編寫一個實現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();
}
}
}
斯科特的答案是一種方法。 您還可以考慮最后使用try {}嗎?
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();
}
}
就個人而言,我認為你已經在考慮這個問題了,這個帖子中的代碼示例過於復雜了。 我不知道為什么人們在他們的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();
}
}
}
}
我認為最好的解決方案是從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
}
}
嗯,我看到沒有人提到這樣做。 您不必擁有在本地聲明的使用中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
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.