views:

1913

answers:

5

My class has the following core:

class SmartDbConnection
{
 private readonly IDbConnection Connection;

 public SmartDbConnection(string ConnectionString)
 {
  if(ConnectionString.Contains("MultipleActiveResultSets=true"))
  {
   Connection = new SqlConnection(ConnectionString);
  }
 }
}

I don't want it to have "SqlConnection" hardcoded. So I thought in making it a Generic class (accepting IDbConnection classes). But I don't know how to do it. Anyone can help?

+8  A: 

Why don't you accept IDbConnection instead of connectionstring to your ctor?

+1: This is a better, more extensible design in general. Refer to Jon Skeet's answer on this same question for a technique if you still want to provide a way for the user of your class to transform the connection string into an IDbConnection.
Greg D
Because I want to have the option to use a single connection if(ConnectionString.Contains("MultipleActiveResultSets=true") or multiple connections if not. If I receive IDbConnection I'll not know how to create more instances of it.
Jader Dias
+2  A: 

Maybe...

class SmartDbConnection<T> where T : IDbConnection, new()
{
    private readonly IDbConnection Connection;

    public SmartDbConnection(string connectionString)
    {
        if (connectionString.Contains("MultipleActiveResultSets=true"))
        {
            Connection = new T();
            Connection.ConnectionString = connectionString;
        }
    }
}

EDIT: But what kaanbardak suggests can be even better...

Fabrizio C.
You could also make T have an interface that specifies it should be able to receive a connection string in its constructor.
GoodEnough
@Crossbrowser: No you can't. Interfaces can't define constructors.
Jon Skeet
@Crossbrowser: I'm almost sure you can't. ;-)
Fabrizio C.
+1  A: 

If you don't want to specify SqlConnection there, where would you specify it - and how would you know to use it only if the connection string contains "MultipleActiveResultSets=true"?

I suspect at some level you want a connection factory - either a Func<string, IDbConnection> you can pass in or set somewhere, or possibly just a class:

public static class ConnectionFactory
{
    public static IDbConnection CreateConnection(string connectionString)
    {
        // Hard-code stuff here
    }
}

Of course, they're just two sides of the same coin - ConnectionFactory is just a static implementation of the Func<string, IDbConnection>.

Jon Skeet
I want specify SqlConnection in the caller code. I will not use it only when "MultipleActiveResultSets=true" because my class has other methods, not shown in this post, that creates a multiples instances for when "MultipleActiveResultSets=false"
Jader Dias
So if the caller code already knows they want a SqlConnection, why don't they pass it in to you?
Jon Skeet
Because "they" don't know if they want 1 or multiple SqlConnections.
Jader Dias
I'm not sure I fully understand. Ah well - so long as you're happy with the accepted answer, it doesn't matter whether I understand or not :)
Jon Skeet
+8  A: 

First - I've added IDisposable to this, as I believe it is important.

Second, note that providers are an alternative here:

class SmartDbConnection
{
    private DbConnection Connection;

    public SmartDbConnection(string provider, string connectionString)
    {
        Connection = DbProviderFactories.GetFactory(provider)
            .CreateConnection();
        Connection.ConnectionString = connectionString;
    }
    public void Dispose() {
        if (Connection != null)
        {
            Connection.Dispose();
            Connection = null;
        }
    }
}

If you must go generic, how about:

class SmartDbConnection<T> : IDisposable where T : class,
    IDbConnection, new()
{
    private T Connection;

    public SmartDbConnection(string connectionString)
    {
        T t = new T();
        t.ConnectionString = connectionString;
        // etc
    }
    public void Dispose() {
        if (Connection != null)
        {
            Connection.Dispose();
            Connection = null;
        }
    }
}
Marc Gravell
provider would be something like "SqlConnection" I presume
Jader Dias
what's the function of the "new()" in "where T : class, IDbConnection, new()" ?
Jader Dias
That allows you to use new T() in the constructor
Marc Gravell
"System.Data.SqlClient" for SQL-Server - the same as the provider in the connectionStrings section in the config file; you can add extra providers through config if you need
Marc Gravell
thanks for clarifying, I received the Responses Tab update also
Jader Dias
A: 
  class SmartDbConnection<T> where T: IDbConnection , new()
  {
    private readonly T Connection;

    public SmartDbConnection(string ConnectionString)
    {
      if (ConnectionString.Contains("MultipleActiveResultSets=true"))
      {
        Connection = new T();
        Connection.ConnectionString = ConnectionString;
      }
    }
  }
Serge - appTranslator