2016-10-22 6 views
2

コンソールアプリケーションで実行されるいくつかのコードをリファクタリングしたいと思います。 Appは外部データベースを更新し、MySQLまたはSQL Serverのいずれかをサポートするように最近更新されました。そこで、MySqlConnectionとMySqlCommand(など)を使用するメソッドシグネチャと、SqlConnectionとSqlCommand(など)を使用するメソッドシグネチャがあるため、多数の重複したコードを持つほぼ同じメソッドが2つあります。異なる入力オブジェクトでジェネリック関数を使用するためのリファクタリング

コードは、ADOオブジェクトの明白な違いを除いて、本質的に同一です。

私がしたいことは次のようなものです。私はここでいくつかの投稿を見てきました(例えばHow do I use reflection to call a generic method?のような)と、動的なタイプでこれを設定する方法を示す他のサイトは素晴らしいですが、例のどれもfoo.GetType )を使用して、動的型が正しいことを証明します。

したがって、どのようにそのダイナミックタイプのメソッドを呼び出しますか?もちろん、これを設定しようとすると、sqlConnectionパラメータでOpen()メソッドを呼び出そうとするとコンパイルされません。

ここで私が達成しようとしているものの一種です:事前に

private static void TransferXmlData(ExportManifest m_settings, XmlNodeList xmlNodeList) 
{ 
    if (m_Settings.ServerType.ToLower() == "mysql") 
    { 
     using (MySqlConnection mySqlConnection = new MySqlConnection(m_Settings.TargetData.ConnectionString)) 
     { 
      MySqlCommand mySqlCommand = 
       new MySqlCommand(Program.GetCommandTextTemplate(m_settings), mySqlConnection); 
      PrepareSqlCommand(mySqlConnection, mySqlCommand, m_settings) 
     } 
    } 
    else 
    { 
     using (SqlConnection sqlConnection = 
      new SqlConnection(m_Settings.TargetData.ConnectionString)) 
     { 
      SqlCommand sqlCommand = 
       new SqlCommand(Program.GetCommandTextTemplate(m_settings), sqlConnection); 
      PrepareSqlCommand(sqlConnection, sqlCommand, m_settings) 
     } 
    } 
} 

private static void PrepareSqlCommand<T>(T sqlConnection, T sqlCommand, ExportManifest m_settings) 
{ 
    // Potentially a lot of code here that looks just like the 
    // code in the else block, Except that it uses the 
    // MySqlConnection objects instead of SqlConnection 
    // Do some stuff 
    sqlConnection.Open(); // obviously doesn't work 
} 

ありがとう!

+2

'IDbConnection'と' IDbCommand'を期待してメソッドを作ることはできませんか? – Sehnsucht

答えて

1

工場設計パターンを実装することができます(ジェネリック医薬品と一緒に使いたくない場合は、これについて考えてください) これはコードの重複を防ぐのに役立ちます。

Factoryクラスを実装します。

`

Public class Factory 
    { 
     public static IDbConnection createDbInstance(ExportManifest m_settings) 
     { 
      if (m_Settings.ServerType.ToLower() == "mysql") 
      { 
       return new MySqlConnection(); 

      } 

      else 
       return new SqlConnection(); 
     } 
    } ` 

と一度あなたのデータアクセスコードを記述しますが、されるためにするIDbConnectionとのIDbCommand

private static void TransferXmlData(ExportManifest m_settings, XmlNodeList xmlNodeList) 
{ 
    IDbConnection db = Factory.createDbInstance(m_settings); 
       db.ConnectionString = m_Settings.TargetData.ConnectionString; 
       IDbCommand comnd = db.CreateCommand(); 

       comnd.CommandText = Program.GetCommandTextTemplate(m_settings); 
       comnd.CommandType = CommandType.Text; 
       // db.Open(); if you want to open connection here 
       PrepareSqlCommand(db, comnd, m_settings); 

}

private static void PrepareSqlCommand(IDbConnection sqlConnection, IDbCommand sqlCommand, ExportManifest m_settings) 
{ 
    // Potentially a lot of code here that looks just like the 
    // code in the else block, Except that it uses the 
    // MySqlConnection objects instead of SqlConnection 
    // Do some stuff 
    sqlConnection.Open(); 
} 
0

を使用することができ、あなたの実際の方法でいくつかのロジックに基づいて実装を切り替えることができる場合は、IDbConnectionに対してコーディングする必要があります。

の効果に何か:私の意見で

using (IDbConnection db = new SqlConnection(ConfigurationManager.ConnectionStrings["AdventureWorks"].ConnectionString)) 

     { 

      //execute database actions against IDBConnection    

     } 

、これは非常によくリポジトリパターンを使用して確立され、そしてそれは、データベースの実装の詳細からあなたを保護しますが、パターンの適切な実装が過剰に複雑かもしれませんあなたのユースケース限りどのような接続がnew()になるかを決めるロジックとしては、上記のような工場のアプローチで十分ですが、これが簡単なアプリケーションであれば簡単にenumフラグを渡すことができます。大規模なソフトウェアでは、Inversion of Controlコンテナを使用してIDbConnectionの特定のインスタンスを制御して注入する必要があります。いずれの場合でも、リフレクション、ジェネリックス、ダイナミクスは、ここで間違ったツールになります(オブジェクトマッピング)。 @Sehnsuchtが言ったように

0

は、あなたがそのような何かを行うことができ:

private static void TransferXmlData(ExportManifest m_settings, XmlNodeList xmlNodeList) 
{ 
    if (m_Settings.ServerType.ToLower() == "mysql") 
     Connect(connectionString => new MySqlConnection(connectionString), 
      (text, connection) => new MySqlCommand(text, connection)); 
    else 
     Connect(connectionString => new SqlConnection(connectionString), 
      (text, connection) => new SqlCommand(text, connection)); 
} 

private static void Connect(ExportManifest m_settings, 
    Func<string, IDbConnection> createConnection, 
     Func<string, IDbConnection, IDbCommand> createCommand) 
{ 
    using (IDbConnection mySqlConnection = 
     createConnection(m_Settings.TargetData.ConnectionString)) 
    { 
     IDbCommand mySqlCommand = 
      createCommand(Program.GetCommandTextTemplate(m_settings), mySqlConnection); 
     PrepareSqlCommand(mySqlConnection, mySqlCommand, m_settings); 
    } 
} 

private static void PrepareSqlCommand(IDbConnection sqlConnection, 
    IDbCommand sqlCommand, ExportManifest m_settings) 
{ 
    sqlConnection.Open(); 
} 
両方 SqlConnection

IDbConnectionを実装DbConnectionからMySqlConnection継承。SqlCommandMySqlCommandと同じで、IDbCommandを実装しています。
次に、インターフェイスを使用してコードをマージすることができます。


しかし、何らかの理由で実際の型(戻り値)を使用する必要がある場合は、メソッドを以下のように変更することができます:

private static void Connect<TConnection, TCommand>(ExportManifest m_settings, 
     Func<string, TConnection> createConnection, 
     Func<string, TConnection, TCommand> createCommand) 
    where TConnection : IDbConnection 
    where TCommand : IDbCommand 
{ 
    using (TConnection mySqlConnection = 
     createConnection(m_Settings.TargetData.ConnectionString)) 
    { 
     TCommand mySqlCommand = 
      createCommand(Program.GetCommandTextTemplate(m_settings), mySqlConnection); 
     PrepareSqlCommand(mySqlConnection, mySqlCommand, m_settings); 
    } 
} 

private static void PrepareSqlCommand<TConnection, TCommand>(TConnection sqlConnection, 
     TCommand sqlCommand, ExportManifest m_settings) 
    where TConnection : IDbConnection 
    where TCommand : IDbCommand 
{ 
    sqlConnection.Open(); 
} 
関連する問題