Robert Snyder
Robert Snyder

Reputation: 2409

Polymorphic class using lambda

I'm not sure if this is possible. I'm trying to learn a little bit about lambda expressions because of a program that I am writing with my buddy. So he has a Database class that talks with a MS SQL server. I wanted to do some testing on the classes and so made a simple Compact Database that in my TextFixtureSetup I populate the tables (2 tables right now) and then in teardown I delete all the data. his database class uses something like this for his SQL connection

    protected void WithConnection(Action<SqlConnection> sqlBlock)
    {
        try
        {
            using (SqlConnection connection = new SqlConnection(this.ConnectionString))
            {
                connection.Open();
                sqlBlock(connection);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(@"Exception during database connection: {0}", ex);
        }
    }

I think I found a post that Jon Skeet answered using almost the same code. https://stackoverflow.com/a/1063112/1329396

I think that this is cool, but my mock database uses SQLCEReader. I did a little research and found that they share a common class System.Data.Common.DbDataReader and it is only one level up. I haven't checked much with it, but i was thinking about if it was possible to use a polymorphic style way to use the WithConnection style of programming that would allow me to use my SQLCeDataReader and his SQLDataReader. Is there a way to do this

Upvotes: 3

Views: 294

Answers (1)

Dax Fohl
Dax Fohl

Reputation: 10781

Use a factory function. If you can get by with just using a DbConnection for all your Actions you don't need generics:

protected void WithConnection(Action<DbConnection> sqlBlock, Func<DbConnection> dbCxnFactory)
{
    try
    {
        using (DbConnection connection = dbCxnFactory())
        {
            connection.ConnectionString = this.ConnectionString;
            connection.Open();
            sqlBlock(connection);
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine(@"Exception during database connection: {0}", ex);
    }
}

If you want to specialize, some actions to SqlConnection only and some to SqlCeConnection only, then you can make it generic:

protected void WithConnection<T>(Action<T> sqlBlock, Func<T> dbCxnFactory) where T : DbConnection
{
    try
    {
        using (T connection = dbCxnFactory())
        {
            connection.ConnectionString = this.ConnectionString;
            connection.Open();
            sqlBlock(connection);
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine(@"Exception during database connection: {0}", ex);
    }
}

If you don't want to pass in the factory as a parameter, you can use a generic with new()

protected void WithConnection<TCxn>(Action<TCxn> sqlBlock) where TCxn : DbConnection, new()
{
    try
    {
        using (var cxn = new TCxn())
        {
            cxn.ConnectionString = this.ConnectionString;
            cxn.Open();
            sqlBlock(cxn);
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine(@"Exception during database connection: {0}", ex);
    }
}

Upvotes: 5

Related Questions