C # syntax for declaring an abstract generic type variable

I have a class defined as follows:

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

In a particular subclass, I define types as such;

 public class ConcreteRepo : Repository<LSTableClass, LSDataContext> 

At the next level, I have business objects that store the repository object as a private variable.

That was good,

 private ConcreteRepo _repository; 

However, I then redid this into the parent class for all business objects - this parent class contains the repository / implements the Dispose pattern to delete the repository, etc.

My problem is that I just cannot get the syntax for declaring a variable.

The closest I came

 protected Repository<Object, DataContext> _repository; 

but this gives a compilation error:

"Error 1" System.Data.Linq.DataContext "must be a non-abstract type with an open constructor without parameters in order to use it as a parameter" TDataContext "in the generic type or method" .... Repository "..."

I tried other things but ran into other problems.

In the business layer object that inherits this abstract class, I create and use the cast variable _repository;

 (Repository<LSTableClass, LSDataContext>)_repository = new ConcreteRepo(); 
  • and I think it will be good if I get this ad directly in the parent.

If I cannot get this to work, I must declare a _repository in each business object with detailed details and implement a delete pattern in each to clear it. Not the end of the world, but I would not want that.

+4
source share
2 answers

If I understand your problem correctly, you need to add a third general parameter - the type of repository, which should be a descendant of Repository with the corresponding types of arguments.

To outline this a little more:

 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> { // ... 

I know that this is probably not as compact as you would like, but what is needed to effectively reduce this effect, but still preserve strong typing, are more general types of a general order (called class types in Haskell): The method of specifying type parameters themselves is common and can accept type parameters.

+3
source

Your expression

 protected Repository<Object, DataContext> _repository; 

It does not work due to the restriction you imposed on it:

 ... where TDataContext : DataContext, new() 

In particular, the new() .

I assume that you want to โ€œenterโ€ an object that satisfies your universal interface.

Two things:

  • You cannot convert between Repository<Object, DataContext> and Repository<LSTableClass, LSDataContext> . Not with C # 3. This is called contravariance / covariance and will not be available until C # 4. In C # 3, these are two completely different types.

  • If you want to keep the common element inside the class, then the type arguments must be concrete types or must be declared as type parameters in the declaration of the parent class (creation that is generic).

Options:

  • Use generic type arguments for the parent class.
  • Remove the new () constraint from your class declaration.
+3
source

All Articles