2009-07-08 3 views
12

Я столкнулся с проблемой, с которой я просто не могу найти хорошую работу.Перегрузки метода, которые отличаются только общим ограничением

Я хочу, чтобы эти 3 перегрузок:

public IList<T> GetList<T>(string query) where T: string 
public IList<T> GetList<T>(string query) where T: SomeClass 
public IList<T> GetList<T>(string query) where T: struct 

Очевидно, что первое ограничение не будет даже скомпилировать в одиночку, так что это мой первый вопрос. (Я понимаю, что могу просто сделать это IList, но я хочу, чтобы такой же синтаксис для этих трех)

В любом случае, причина в том, что эти методы являются частью оболочки для выполнения SQL-запросов к базе данных - я хочу быть способный возвращать результат в виде списка строк (в случае, если кто-то выбирает столбец varchar), список типов значений (int, float, whatever) или список классов (эти классы представляют таблицы и, следовательно, содержат несколько столбцов)

Я надеюсь, что часть была несколько понятной :-)

В любом случае моя большая проблема, очевидно, в том, что я не могу сделать эти перегрузки, так как они используют одно и то же имя и список параметров.

Кроме того, я не могу объединить их в один и тот же метод, так как мне нужно вызвать метод в SomeClass в этой реализации, поэтому, если я не хочу делать какое-то тяжелое придание тождественности или, что еще хуже, отражение, мне нужно это ограничение.

Я понимаю, что то, что я пытаюсь сделать, невозможно, поэтому я ищу хороший подход, который подражает моим намерениям.

Если некоторые это немного неясно, не стесняйтесь спрашивать :-)

Edit:

Вот мой текущий код «где T: SomeClass» версии. Я пытаюсь добавить поддержку строк/типов значений для этого текущего кода, так что, может быть, мой первоначальный подход просто неправильно - любые идеи приветствуются в основном :-)

public IList<TValue> GetList<TValue>(string query) where TValue : DbTable, new() 
{ 
    DataSet dataSet = GetDataSet(query); 
    IList<TValue> result = new List<TValue>(); 

    if (dataSet.Tables.Count > 0) 
    { 
     foreach (DataRow row in dataSet.Tables[0].Rows) 
     { 
      TValue col = new TValue(); 
      col.Fill(row); 
      result.Add(col); 
     } 
    } 

    return result; 
} 

Как вы можете видеть, что я нужен точный тип из DbTable, чтобы создать новый конструктор. Fill - абстрактный метод DbTable (который является абстрактным классом).

ответ

10

Как вы заметили; для этого нет хороших вариантов. Вы можете рассматривать разные имена (а не перегрузки) - GetStringList и т. Д.

Однако, интересно, было бы проще отказаться от ограничения. Единственный тип проверки с «как» - это не совсем «тяжелый» тип-литье, и это может сэкономить много боли.

+0

Да, разные имена просты, однако я хочу сделать это почти так, как если бы это был один и тот же метод, который учитывает эти ограничения. Я мог бы сделать GetList без ограничений, а затем выбросить исключение, если тип неправильный - однако в случае с SomeClass это фактически классы, которые наследуют SomeClass, и мне нужен точный тип, так как я их new(). Подождите несколько секунд, и я отправлю свой существующий GetList где T: Код SomeClass. – Steffen

+0

В этом случае он может запутаться с 'MakeGenericMethod' и т. Д .; не очень хороший вариант. –

+0

Точно - и вы правы, что простая проверка типов для строк и ценностей не является трудной. Он забирает детей с DbTable, о которых я беспокоюсь. – Steffen

0

что об этом?

public IList<T> GetList<T>(string query) where T : new() 
{ 
    // whatever you need to distinguish, this is a guess: 
    if (typeof(T).IsPrimitiveValue) 
    { 
    GetPrimitiveList<T>(query); 
    } 
    else if (typeof(T) == typeof(string)) 
    { 
    GetStringList<T>(query); 
    } 
    else 
    { 
    GetEntityList<T>(query); 
    } 

} 

private IList<T> GetStringList<T>(string query) 

private IList<T> GetPrimitiveList<T>(string query) 

private IList<T> GetEntityList<T>(string query) 
+0

Да, это почти сработало, единственной проблемой является GetEntityList - как вы можете видеть из моего примера кода, мне нужно иметь возможность new() T и называть Fill на нем - невозможно без ограничения * или * отражения (чего я бы предпочел) Остальное, однако, было бы прекрасно. – Steffen

+0

Вам понадобится проверка выполнения для реализации интерфейсов («как»). Отражение не требуется. Или - сделайте методы с определенными именами (GetEntityList) общедоступными и вызовите их напрямую. –

+0

Stefan - У меня, по крайней мере, дюжина реализаций DbTable (так как у меня есть класс для каждой таблицы в моей базе данных), поэтому тестирование с использованием не реально выполнимо, кроме того, что реализации обычно выходят за рамки библиотеки. Что касается прямого вызова, я начинаю верить, что на самом деле это единственное решение: -/ – Steffen

Смежные вопросы