Как сделать этот класс универсальным? (.NET С#)

Мой класс имеет следующее ядро:

class SmartDbConnection
{
    private readonly IDbConnection Connection;

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

Я не хочу, чтобы "SqlConnection" был жестко запрограммирован. Поэтому я решил сделать его универсальным классом (принимая классы IDbConnection). Но я не знаю, как это сделать. Кто-нибудь может помочь?


person Jader Dias    schedule 16.01.2009    source источник


Ответы (4)


Во-первых, я добавил к этому IDisposable, так как считаю это важным.

Во-вторых, обратите внимание, что провайдеры являются альтернативой здесь:

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;
        }
    }
}

Если вы должны перейти на общий язык, как насчет:

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;
        }
    }
}
person Marc Gravell    schedule 16.01.2009
comment
провайдер будет чем-то вроде SqlConnection, я полагаю - person Jader Dias; 16.01.2009
comment
какова функция new(), где T: class, IDbConnection, new()? - person Jader Dias; 16.01.2009
comment
Это позволяет вам использовать новый T() в конструкторе - person Marc Gravell; 16.01.2009
comment
System.Data.SqlClient для SQL-Server — то же, что и провайдер в секции connectionStrings в конфиг-файле; вы можете добавить дополнительных провайдеров через конфигурацию, если вам нужно - person Marc Gravell; 16.01.2009
comment
спасибо за уточнение, я также получил обновление вкладки ответов - person Jader Dias; 16.01.2009

Почему вы не принимаете IDbConnection вместо строки подключения к вашему ctor?

person user53378    schedule 16.01.2009
comment
+1: в целом это лучший, более расширяемый дизайн. Обратитесь к ответу Джона Скита на этот же вопрос, чтобы узнать о методе, если вы все еще хотите предоставить пользователю вашего класса способ преобразовать строку подключения в IDbConnection. - person Greg D; 16.01.2009
comment
Потому что я хочу иметь возможность использовать одно соединение if(ConnectionString.Contains(MultipleActiveResultSets=true) или несколько соединений, если нет. Если я получу IDbConnection, я не буду знать, как создать больше его экземпляров. - person Jader Dias; 16.01.2009

Может быть...

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;
        }
    }
}

РЕДАКТИРОВАТЬ: Но то, что предлагает kaanbardak, может быть даже лучше...

person Fabrizio C.    schedule 16.01.2009
comment
Вы также можете сделать так, чтобы T имел интерфейс, указывающий, что он должен иметь возможность получать строку подключения в своем конструкторе. - person mbillard; 16.01.2009
comment
@Crossbrowser: Нет, нельзя. Интерфейсы не могут определять конструкторы. - person Jon Skeet; 16.01.2009
comment
@Crossbrowser: я почти уверен, что ты не сможешь. ;-) - person Fabrizio C.; 16.01.2009

Если вы не хотите указывать там SqlConnection, где бы вы его указали - и как бы вы узнали, использовать ли его только в том случае, если строка подключения содержит "MultipleActiveResultSets=true"?

Я подозреваю, что на каком-то уровне вам нужна фабрика соединений - либо Func<string, IDbConnection>, которую вы можете передать или установить где-то, либо, возможно, просто класс:

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

Конечно, это всего лишь две стороны одной медали — ConnectionFactory — это просто статическая реализация Func<string, IDbConnection>.

person Jon Skeet    schedule 16.01.2009
comment
Я хочу указать SqlConnection в коде вызывающего абонента. Я не буду использовать его только тогда, когда MultipleActiveResultSets=true, потому что в моем классе есть другие методы, не показанные в этом посте, которые создают несколько экземпляров, когда MultipleActiveResultSets=false - person Jader Dias; 16.01.2009
comment
Итак, если вызывающий код уже знает, что ему нужен SqlConnection, почему бы ему не передать его вам? - person Jon Skeet; 16.01.2009
comment
Потому что они не знают, хотят ли они 1 или несколько SqlConnections. - person Jader Dias; 16.01.2009
comment
Я не уверен, что полностью понимаю. Ну ладно - пока вы довольны принятым ответом, не имеет значения, понимаю я или нет :) - person Jon Skeet; 16.01.2009