Синтаксис C # для объявления переменной абстрактного универсального типа - PullRequest
4 голосов
/ 05 мая 2009

У меня есть класс, определенный следующим образом:

public abstract class Repository<TEntity, TDataContext> : DisposableBaseClass
   where TEntity : class
   where TDataContext : DataContext, new()
{...contains Linq to SQL related functionality

В конкретном подклассе я определяю типы так:

public class ConcreteRepo : Repository<LSTableClass, LSDataContext>

На следующем уровне у меня есть бизнес-объекты, которые хранят объект Repository в качестве закрытой переменной.

Это было хорошо;

private ConcreteRepo _repository;

Однако затем я реорганизовал это в родительский класс для всех бизнес-объектов - этот родительский класс содержит репозиторий / реализует шаблон Dispose для удаления репозитория и т. Д.

Моя проблема в том, что я просто не могу получить правильный синтаксис для объявления переменной.

Самое близкое, что я пришел, это;

protected Repository<Object, DataContext> _repository;

но это дает ошибку компиляции:

"Ошибка 1 'System.Data.Linq.DataContext' должна быть неабстрактного типа с открытым конструктором без параметров, чтобы использовать его как параметр 'TDataContext' в универсальном типе или методе '... .Repository»..."

Я пробовал разные вещи, но решал другие проблемы.

В объекте бизнес-уровня, наследующем этот абстрактный класс, я создаю и использую переменную _repository с приведением типа;

(Repository<LSTableClass, LSDataContext>)_repository = new ConcreteRepo();
  • и я думаю, что все будет в порядке, при условии, что я могу получить эту декларацию прямо в родителе.

Если я не могу заставить это работать, я должен объявить _repository в каждом бизнес-объекте с полными / конкретными деталями типа и реализовать шаблон dispose в каждом из них, чтобы прояснить ситуацию. Не конец света, но я бы не хотел.

Ответы [ 2 ]

3 голосов
/ 05 мая 2009

Ваша декларация

protected Repository<Object, DataContext> _repository;

Не сработало из-за ограничений, наложенных на него:

...    
where TDataContext : DataContext, new()

В частности, new() часть.

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

Две вещи:

  • Нельзя конвертировать между Repository<Object, DataContext> и Repository<LSTableClass, LSDataContext>. Не с C # 3. Это называется Contravariance / Covariance и не будет доступно до C # 4. В C # 3 это два совершенно разных типа.

  • Если вы хотите сохранить универсальный член внутри класса, то аргументы типа должны быть либо конкретными типами, либо они должны быть объявлены как параметры типа в объявлении родительского класса (делая that универсальный).

Параметры:

  • Используйте аргументы универсального типа в родительском классе.
  • Удалите ограничение new () из вашего объявления класса.
3 голосов
/ 05 мая 2009

Если я правильно понимаю вашу проблему, вам нужно добавить третий универсальный параметр, тип репозитория, который должен быть потомком Repository с соответствующими типами аргументов.

Чтобы обрисовать это еще немного:

public abstract class Repository<TEntity,TDataContext>
    where TEntity : class
    where TDataContext : DataContext, new() {}

public abstract class BusinessObject<TEntity,TDataContext,TRepository>
    where TEntity : class
    where TDataContext : DataContext, new()
    where TRepository : Repository<TEntity,TDataContext>
{
    TRepository _repository;
}

public class ConcreteObject : BusinessObject<LSTableClass,LSDataContext,ConcreteRepo>
{ // ...

Я знаю, что он, вероятно, не так компактен, как хотелось бы, но для эффективного уменьшения этого значения, но при этом все еще сохраняется строгая типизация, это универсальные типы более высокого порядка (называемые классами типов в Haskell): способ указания параметров этого типа сами по себе являются общими и могут принимать параметры типа.

...