jeudi 20 avril 2017

C# reflection - choosing constructor overload based on available parameters

I've written a generic database class which can be called to carry out common database (CRUD) operations to save re-writing the ADO.NET code in multiple solutions. To make this flexible, there are a number of constructor overloads based on the different database authentication types and instance types etc. The class is as follows:

class Database
{
    // default instance with Windows authentication
    // constructor 1
    public Database(string server, string database, bool persistSecurityInfo)
    {
        _server = server;
        _database = database;
        _persistSecurityInfo = persistSecurityInfo;
        _integratedSecurity = "True";
        _connectionString = "Data Source=" + server + ";Initial Catalog=" + database + ";Persist Security Info=" + persistSecurityInfo.ToString() + ";Integrated Security=True";
    }

    // named instance using Windows authentication
    // constructor 2
    public Database(string server, string instance, string database, bool persistSecurityInfo) : this(server, database, persistSecurityInfo)
    {
        _instance = instance;
        _integratedSecurity = "True";
        _connectionString = "Data Source=" + server + "\\" + instance + ";Initial Catalog=" + database + ";Persist Security Info=" + persistSecurityInfo.ToString() + ";Integrated Security=True";
    }

    // default instance with SQL authentication
    // constructor 3
    public Database(string server, string database, bool persistSecurityInfo, string userName, string password) : this(server, database, persistSecurityInfo)
    {
        _userName = userName;
        _password = password;
        _integratedSecurity = "False";
        _connectionString = "Data Source=" + server + ";Initial Catalog=" + database + ";Persist Security Info=" + persistSecurityInfo.ToString() + ";User ID=" + userName + ";Password=" + password;
    }

    // named instance with SQL authentication
    // constructor 4
    public Database(string server, string instance, string database, bool persistSecurityInfo, string userName, string password) : this(server, database, persistSecurityInfo, userName, password)
    {
        _instance = instance;
        _integratedSecurity = "False";
        _connectionString = "Data Source=" + server + "\\" + instance + ";Initial Catalog=" + database + ";Persist Security Info=" + persistSecurityInfo.ToString() + ";User ID=" + userName + ";Password=" + password;
    }

    private string _server;
    private string _instance;
    private string _database;
    private bool _persistSecurityInfo;
    private string _userName;
    private string _password;
    private string _integratedSecurity;

    private string _connectionString;
    private string _query;

    //CRUD Methods here
}

I have written a console application which is writing to a database. When the application is executed, the user provides some command line switches.

Some of the switches are as follows (There are others relating to the program's operation which I have not included here):

  • /s : database server name
  • /i : database instance name
  • /d : database name
  • /n : integrated security (True or False)
  • /u : db Username
  • /p : db Password

/i, /u and /p are optional (EG if an instance name isn't supplied, the program assumes it is to connect to a default instance on /s)

Therefore, I need the program to, at run time decide which constructor to call based on which arguments have been provided.

pseudo example here

Class Program
{
    static void Main(string[] args)
    {
         foreach (string arg in args[])
         {
             //code to work out which parameters have been provided here and adds them to array. Also other code which checks integrity such as ensuring there is no username without a password and vice versa etc.
             string[] suppliedParameters;

             //if there is a /i , /u , /p parameters, use constructor 4
             //if there is a /u and /p but no /i, use constructor 3
             //if there is an /i but no /u or /n use constructor 2
             //if there is no /i, /u or /n, use constructor 1
         }
    }
}

I know I can use reflection to execute the relevant constructor and that I could achieve selection of the constructor using a switch statement in the Main method which carries out the tests in the logic above but am just wondering if there is a maybe a more elegant way to do this?





Aucun commentaire:

Enregistrer un commentaire