jspavs
jspavs

Reputation: 23

Ensuring interface implementations have the correct subclass for method

I'm designing a database interface, and am writing a method to add a table to the database. Different databases may need different parameters to add tables, so to solve that, I've made an abstract class for database parameters. An example which uses GoogleSheets:

public abstract class DatabaseTableParameters 
{
    public string Key { get; set; }
    
    public DatabaseTableParameters(string key) {
        Key = key;
    }
}

public class GoogleSheetParameters : DatabaseTableParameters
{
    public int RangeColumnStart { get; set; }
    public int RangeRowStart { get; set; }
    public int RangeColumnEnd { get; set; }
    public bool FirstRowIsHeaders { get; set; }

    public GoogleSheetParameters(string key, int columnStart, int rowStart, int columnEnd, bool firstRowIsHeaders = false) : base(key)
    {
        RangeColumnStart = columnStart;
        RangeRowStart = rowStart;
        RangeColumnEnd = columnEnd;
        FirstRowIsHeaders = firstRowIsHeaders;
    }
}

The interface then has a method for adding a table to the database.

interface IDatabase<T>
{
    void AddTable(DatabaseTableParameters param);

}

The problem is that implementations of the database need to be restricted to a certain subclass of DatabaseTableParameters. I could use reflection to ensure that the passed parameter is the correct type, but that seems a little fragile to me.

Is there a better was of ensuring the correct parameter type is passed in?

Upvotes: 0

Views: 67

Answers (2)

John Wu
John Wu

Reputation: 52210

Define your table parameters with a constraint that identifies what table type it goes with.

public abstract class DatabaseTableParameters<T> 
{
    public string Key { get; set; }

    public DatabaseTableParameters(string key) {
        Key = key;
    }
}

public class GoogleSheetParameters : DatabaseTableParameters<GoogleTable>
{
    //Etc...

Then define your database using this constraint:

interface IDatabase<T>
{
    void AddTable<T>(DatabaseTableParameters<T> param);
}


class GoogleSheetDatabase : IDatabase<GoogleTable>
{
    //etc....

This will force the Add method to require the appropriate type of parameters at compile time.

Upvotes: 1

aybe
aybe

Reputation: 16652

Something like this, you can add Table1 but not Table2 thanks to where

public interface ITable
{
    string Key { get; set; }
}

public abstract class TableBase : ITable
{
    public string Key { get; set; }
}

public interface ITableExt
{
    int A { get; set; }

    string Key { get; set; }
}

public class Table1 : TableBase, ITableExt
{
    public int A { get; set; }
}

public class Table2 : TableBase
{
    public int A { get; set; }
}

class Test
{
    public Test()
    {
        Add(new Table1());
        // Add(new Table2()); // not possible
    }
    public void Add<T>(T value) where T : TableBase, ITableExt
    {

    }
}

Upvotes: 0

Related Questions