views:

2289

answers:

3

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 the concrete sub-class I define the types as so;

public class ConcreteRepo : Repository<LSTableClass, LSDataContext>

At the next tier up, I have business objects which hold the Repository object as a private variable.

This was fine;

private ConcreteRepo _repository;

However, I then refactored this out into a parent class for all the business objects - this parent class holds the repository/ implements Dispose pattern to dispose of repository etc.

My problem is that I just can't get the syntax right for the declaration of the variable.

The closest I have come is;

protected Repository<Object, DataContext> _repository;

but this gives the compile error:

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

I've tried various other things but hit other problems.

In the business layer object inheriting this abstract class I am creating and using the _repository variable with a cast;

(Repository<LSTableClass, LSDataContext>)_repository = new ConcreteRepo();
  • and I think this will be fine, assuming I can get this declaration right in the parent.

If I can't get this to work I have to declare the _repository in each business object, with the full/ concrete type details, and implement the dispose pattern in each one to clear up. Not the end of the world, but I'd like to not have to.

+2  A: 

If I understand your problem correctly, you need to add a third generic parameter, the repository type, which is constrained to be a descendant of Repository with the appropriate argument types.

To outline it some 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 it's probably not as compact as you would like, but what's needed to reduce this down effectively yet still retain the strong typing, is higher order generic types (called type classes in Haskell): a way of indicating that type parameters are themselves generic, and can take type parameters.

Barry Kelly
Thanks Barry, this is exactly what I needed, all working now, thanks very much
DannykPowell
+1  A: 

Your declaration

protected Repository<Object, DataContext> _repository;

Didn't work because of the constraint you placed upon it:

...    
where TDataContext : DataContext, new()

Specifically the new() part.

I'm guessing that you want to 'inject' an object satisfying your generic interface.

Two things:

  • You can't convert between Repository<Object, DataContext> and Repository<LSTableClass, LSDataContext>. Not with C# 3. This is called Contravariance/Covariance and won't be available until C# 4. In C# 3 these are two completely different types.

  • If you want to store a generic member inside of a class, then the type arguments either have to be concrete types, or they must be declared as type parameters in the parent class declaration (making that generic).

Options:

  • Use generic type arguments on your parent class.
  • Remove the new() constraint from your class declaration.
Matt Brunell
Thanks for the answer Matt; unfortunately it seems I can only mark one answer as the correct answer, otherwise I would mark yours too. I went with the first option as you put them, as you were correct in your guess that I need to inject an object so need to retain the new() constraint. Thanks again for the answer
DannykPowell
A: 

How to declare a C# varialble into an HTML type variable

if you have any decalaration of any C# variable in ASP.NET like a label or a text box type and in order for html or the client side of your web to be able to read what is on that decaration of the C# variable that you have declared this can do:

input type="hidde" name="name_type" value='textbox1.Text'



                                                [by College of Saint Benilde]
Marlo la O'