Обработка классов, присущих абстрактному классу и параметру типа

У меня есть базовый абстрактный класс и его параметр абстрактного типа:

public abstract class Database<T> where T : DatabaseItem, new() {
  protected List<T> _items = new List<T> ();
  protected virtual void Read (string[] cols)   {
    T item = new T ();
    ...
}

public abstract class DatabaseItem {
  ...
}

Затем у меня есть ряд дочерних классов, присущих ему:

public class ShopDatabase : Database<ShopItem> {}
public class ShopItem : DatabaseItem {}

public class WeaponDatabase : Database<WeaponItem> {}
public class WeaponItem : DatabaseItem {}

...

Теперь я хочу поместить Dictionary для отслеживания баз данных и метод их возврата с использованием типа DatabaseItem, примерно так:

Dictionary<Type, Database<DatabaseItem>> databases;

public static Database<T> GetDatabase<T> () where T: DatabaseItem {
  return databasebases [typeof (T)];
}

Затем он дал мне ошибку «'T' должен быть неабстрактным типом с общедоступным конструктором без параметров, чтобы использовать его как параметр 'T'», потому что DatabaseItem является абстрактным . Я сделал DatabaseItem неабстрактным типом, ошибка исчезла, но все равно появилось много ошибок преобразования типа ...

Нашел аналогичный вопрос но я все еще не понимаю ...

Какое решение / структура лучше для этого?


person Richard Fu    schedule 16.12.2015    source источник
comment
Возможно, чтобы определить интерфейс для вашего класса базы данных, например Dictionary ‹Type, IDatabase›   -  person Matt Searles    schedule 16.12.2015


Ответы (2)


Самое простое, что вы можете сделать, - это сохранить Database<T> потомков как объекты:

static class DatabaseManager
{
    private static Dictionary<Type, object> databases = new Dictionary<Type, object>();

    // ....

    public static Database<T> GetDatabase<T>()
        where T : DatabaseItem, new()
    {
        return (Database<T>)databases[typeof(T)];
    }
}

Даже если вы превратите DatabaseItem в неабстрактный класс с конструктором без параметров, это тоже не поможет, потому что typeof(Database<ShopItem>) != typeof(Database<DatabaseItem>).

Обратите внимание, что общие ограничения для метода GetDatabase<T> должны быть такими же, как и для класса Database<T>.

Upd.

есть ли способ узнать, какой параметр типа использует класс? например отдавая ShopDatabase, я хочу получить ShopItem. Он мне нужен при инициализации словаря баз данных

Используйте отражение:

var databaseItemType = typeof(ShopDatabase).BaseType.GetGenericArguments()[0];

Для таких случаев:

class FooDatabase : Database<FooItem> {}
class BooDatabase : FooDatabase {}
// etc...

вам нужно будет просмотреть дерево наследования, чтобы найти Database<FooItem>.

person Dennis    schedule 16.12.2015
comment
Я думаю, мы почти достигли цели, есть ли способ узнать, какой параметр типа использует класс? например отдавая ShopDatabase, я хочу получить ShopItem. Он мне нужен, когда я инициализирую словарь баз данных - person Richard Fu; 17.12.2015

Плохая новость в том, что вы не можете использовать свой код без приведения типов. Определите неуниверсальный тип или интерфейс для базы данных, затем используйте этот код:

Dictionary<Type, Database> databases;
public static Database<T> GetDatabase<T>() where T: DatabaseItem, new()
{
    return databasebases[typeof(T)] as Database<T>;
}
person Vadim Martynov    schedule 16.12.2015