C # sintaxe para declarar uma variável de um tipo genérico abstrato
-
03-07-2019 - |
Pergunta
Eu tenho uma classe definida da seguinte forma;
public abstract class Repository<TEntity, TDataContext> : DisposableBaseClass
where TEntity : class
where TDataContext : DataContext, new()
{...contains Linq to SQL related functionality
Em concreto sub-classe I definir os tipos como tal;
public class ConcreteRepo : Repository<LSTableClass, LSDataContext>
No próximo nível, eu tenho objetos de negócios que mantêm o objeto Repository como uma variável privada.
Este foi excelentes;
private ConcreteRepo _repository;
No entanto, eu então reformulado isso em uma classe pai para todos os objetos de negócios -. Esta classe pai mantém o padrão Dispose repositório / utensílios de dispor de repositório etc
O meu problema é que eu simplesmente não consegue obter o direito sintaxe para a declaração da variável.
O mais próximo que eu vim é;
protected Repository<Object, DataContext> _repository;
mas isso dá o erro de compilação:
"Erro 1 'System.Data.Linq.DataContext' deve ser um tipo não-abstrato com um construtor sem parâmetros pública, a fim de usá-lo como parâmetro 'TDataContext' no tipo genérico ou método' ... .Repository' ... "
Eu tentei várias outras coisas mas bateu outros problemas.
No objeto camada de negócios herdar essa classe abstrata eu estou criando e usando a variável _repository com um elenco;
(Repository<LSTableClass, LSDataContext>)_repository = new ConcreteRepo();
- e eu acho que isso vai ficar bem, supondo que eu posso obter este direito declaração no pai.
Se eu não posso chegar a este trabalho eu tenho que declarar a _repository em cada objeto de negócios, com os detalhes completos / concreto tipo, e implementar o padrão Dispose em cada um para esclarecer. Não é o fim do mundo, mas eu gostaria de não ter de.
Solução
Se eu entender o seu problema corretamente, você precisa adicionar um terceiro parâmetro genérico, o tipo de repositório, que é obrigado a ser um descendente de Repository
com os tipos de argumento apropriado.
Para delinear um pouco mais:
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>
{ // ...
Eu sei que provavelmente não é tão compacto quanto você gostaria, mas o que é necessário para reduzir esse baixo ainda efetivamente ainda mantêm a tipagem forte, é de ordem superior tipos genéricos (classes chamado tipo em Haskell): uma forma de indicar que parâmetros de tipo são eles próprios genérico, e pode levar parâmetros de tipo.
Outras dicas
A sua declaração
protected Repository<Object, DataContext> _repository;
não funcionou por causa da restrição que você colocou sobre ele:
...
where TDataContext : DataContext, new()
Especificamente a parte new()
.
Eu estou supondo que você quer 'injetar' um objeto satisfazer a sua interface genérica.
Duas coisas:
-
Você não pode converter entre
Repository<Object, DataContext>
eRepository<LSTableClass, LSDataContext>
. Não com C # 3. Isso é chamado Contravariance / Covariance e não estará disponível até C # 4. Em C # 3 estes são dois tipos completamente diferentes. -
Se você quiser armazenar um dentro membro do genérico de uma classe, em seguida, os argumentos de tipo ou tem que ser tipos de concreto, ou eles devem ser declarados como parâmetros de tipo na declaração da classe pai (fazendo que genérico).
Opções:
- Usar argumentos de tipo genérico em sua classe pai.
- Remova a nova restrição () de sua declaração de classe.