Implicit conversion en C# generic classes - c#

I have an application that is structured as an service layer wich uses a repository layer for persistence.
I'm trying to create a generic controller class to reuse shared behavior but I'm having trouble trying to set the generic parameters. The following code:
public class BusinessEntity
{ }
public class Person : BusinessEntity
{ }
public interface IRepository<T> where T : BusinessEntity
{ }
public interface IService<T, R>
where T : BusinessEntity
where R : IRepository<T>
{ }
public partial interface IPersonRepository : IRepository<Person>
{ }
public interface IPersonService : IService<Person, IPersonRepository>
{ }
public abstract class BaseController<X, Y>
where X : BusinessEntity
where Y : IService<X, IRepository<X>>
{ }
public class PersonController : BaseController<Person, IPersonService>
{ }
fails at compilation with
The type ConsoleApplication.IPersonService cannot be used as type parameter Y in the generic type or method ConsoleApplication.BaseController<X,Y>. There is no implicit reference conversion from ConsoleApplication.IPersonService to ConsoleApplication.IService<ConsoleApplication.Person,ConsoleApplication.IRepository<ConsoleApplication.Person>>
this works
public interface IPersonService : IService<Person, IRepository<Person>>
but I lose the custom repository
There is a way to make the compiler realize IPersonRepository is an IRepository<Person>?

public class BusinessEntity
{ }
public class Person : BusinessEntity
{ }
public interface IRepository<T> where T : BusinessEntity
{ }
public interface IService<T, R>
where T : BusinessEntity
where R : IRepository<T>
{ }
public partial interface IPersonRepository : IRepository<Person>
{ }
public interface IPersonService : IService<Person, IPersonRepository>
{ }
public abstract class BaseController<X, Y, Z>
where X : BusinessEntity
where Y : IService<X, Z>
where Z : IRepository<X>
{ }
public class PersonController : BaseController<Person, IPersonService, IPersonRepository>
{ }
To address your comment:
IPersonService can extend the base service class to add custom facilities, like FindPersonsUnderAge(). For this it requires a custom repository. Actually LINQ avoids a lot of custom repository code, but sometimes they are required.
Couldn't IPersonService do that without requiring the repository type to be a type parameter? For example:
public interface IService<T> where T : BusinessEntity { }
public interface IPersonService : IService<Person>
{
IEnumerable<Person> FindPersonsByAge(double minAge, double maxAge);
}
public class Service<T, R> : IService<T>
where T : BusinessEntity
where R : IRepository<T>
{ }
public class PersonService : Service<Person, IPersonRepository>, IPersonService
{ }

Thanks to sll for pointing me in the right direction
public interface IService<T, out R>
where T : BusinessEntity
where R : IRepository<T>
{ }
does the trick

Related

How to define Generic interfaces with multiple inheritance?

I have the following generic interface structure:
public interface IBase {}
public interface IBase<TBase> : IBase
where TBase : class, IBase
{
IEnumerable<IA<TBase>> Derived { get; }
}
public interface IA {}
public interface IA<TBase> : IA
where TBase : class, IBase
{
IEnumerable<IB<TBase, IA<TBase>>> DerivedOfA { get; }
}
public interface IB {}
public interface IB<TBase, TA> : IB
where TBase : class, IBase
where TA : class, IA<TBase>
{
IEnumerable<IC<TBase, TA, IB<TBase, TA>>> DerivedOfB { get; }
}
public interface IC {}
public interface IC<TBase, TA, TB> : IC
where TBase : class, IBase
where TA : class, IA<TBase>
where TB : class, IB<TBase, TA>
{
}
The purpose of this interface structure is to define a contract of type objects in the heirarcy structure.
When I try to define the following:
public class Base : IBase
{
public IEnumerable<IA<Base>> Derived { get; }
public class DerivedA : IA<Base>
{
public IEnumerable<IB<Base , IA<Base>>> DerivedOfA { get; }
public class DerivedB : IB<Base, DerivedA>
{
public IEnumerable<IC<Base, IA<Base>, IB<Base, IA<Base>>>> DerivedOfB { get; }
}
}
}
Everything compiles.
But when I define the 3rd nesting level (IC) compilation fails.
public class Base : IBase
{
public IEnumerable<IA<Base>> Derived { get; }
public class DerivedA : IA<Base>
{
public IEnumerable<IB<Base, IA<Base>>> DerivedOfA { get; }
public class DerivedB : IB<Base, DerivedA>
{
public IEnumerable<IC<Base, IA<Base>, IB<Base, IA<Base>>>> DerivedOfB { get; }
public class DerviedC: IC<Base, DerivedA, DerivedB>
{
}
}
}
(this creates a strict inheritance between the objects with the fact that the classes are nested).
When I write the code, the compiler complains on the following line
public class DerviedC: IC<Base, DerivedA, DerivedB> <-----
with the following error message
Error CS0311 The type 'Base.DerivedA.DerivedB' cannot be used as type parameter 'TB' in the
generic type or method 'IC<TBase, TA, TB>'. There is no implicit reference conversion from
'Base.DerivedA.DerivedB' to 'IB<Base, Base.DerivedA>'.
It seems the 2nd inheritance level of the interfaces is not supported. Why?
As Base.DerivedB inherits IB<Base, DerivedA> I would assume the compiler will no how to up-cast the object to its reference.
How can I resolve this?

Classes coupled with each other by generics

I'm currently learning C# and I'm coming from Java. In Java, I can do something like this:
public interface BasePresenterView<T extends BaseActivityPresenter> {}
public interface BaseActivityPresenter<T extends BasePresenterView> {}
and in C# I'm having a hard time achieving the same thing.
This is called generic constrained in .NET.
Your example in C# will look like this.
public interface BasePresenterView<T> where T: 'Interface or Type'{}
public interface BaseActivityPresenter<T> where T: 'Interface or Type' {}
More info: https://msdn.microsoft.com/en-us/library/d5x73970.aspx
EDIT: As already mentioned circular dependencies are not possible in C#, so you can not constraint them in the same way as in your example.
You want something like this if you are using abstract base classes...
public abstract class MyBasePresenter
{
}
public abstract class MyBasePresenter<TView> : MyBasePresenter
where TView : MyBaseView
{
}
public abstract class MyBaseView
{
}
public abstract class MyBaseView<TPresenter> : MyBaseView
where TPresenter : MyBasePresenter
{
}
public class MyView : MyBaseView<MyPresenter>
{
}
public class MyPresenter : MyBasePresenter<MyView>
{
}
... do this if you want interfaces ...
public interface IMyPresenter
{
}
public interface IMyPresenter<TView> : IMyPresenter
where TView : IMyView
{
}
public interface IMyView
{
}
public interface IMyView<TPresenter> : IMyView
where TPresenter : IMyPresenter
{
}
public class MyView : IMyView<MyPresenter>
{
}
public class MyPresenter : IMyPresenter<MyView>
{
}
... of you really want to go crazy you can even nest the generics ...
public class MyView : IMyView<IMyPresenter<IMyView>>
{
}
You can use generic type constraints, which restrict compile-time types using inheritance.
public interface BasePresenterView<T> where T : IBaseView
Because inheritance cannot be circular, you cannot have the circular dependancy as in the question.
However, if they declare the same methods or properties, they could inherit the same interface:
public interface BasePresenterView : IBaseView
public interface BaseActivityPresenter : IBaseView
I think I resolved it :)
public interface BaseActivityPresenter<T, K>
where T : BasePresenterView<T, K>
where K : BaseActivityPresenter<T, K> {}
public interface BasePresenterView<T, K>
where T : BasePresenterView<T, K>
where K : BaseActivityPresenter<T, K> {}
That seems to be working... for now. I don't know if this is a proper approach.

Can someone explain why this isn't valid implementation?

public class ServiceCodeController : ControllerBase {
// the red squiggly under IJobRepository is saying it's not convertible
private LazyRepo<IJobRepository> _domainRepo2;
}
public class LazyRepo<TRepo> where TRepo : IRepository<IDomainEntity> { ... }
public interface IJobRepository : IRepository<JobDomain>, IListRepository { ... }
public interface IRepository<T> : IRepositoryRead<T>,
IRepositoryCreate<T>,
IRepositoryDelete<T>,
IRepositoryUpdate<T>
where T : IDomainEntity { ... }
public class JobDomain : BaseDomainEntity { ... }
public abstract class BaseDomainEntity : IDomainEntity,
IDomainEntityModifiable,
IDomainEntityActivatable,
IDomainEntityNameable { ... }
My thinking is that LazyRepo takes something that implements IRepository that takes something that implements IDomainEntity. As you can see, IJobRepository implements IRepository that takes JobDomain that inherits from BaseDomainEntity which, at long last, implements IDomainEntity.
For my money, this should work for setting up the LazyRepo class.
Can someone explain to me why I'm getting this error? The type 'IJobRepository' cannot be used as type parameter 'TRepo' in the generic type or method 'LazyRepo'. There is no implicit reference conversion from 'IJobRepository' to 'IRepository'
I think this is where the concepts of contravariance and covariance come in.
A covariant interface allows its methods to return more derived types than those specified in the interface. A contravariant interface allows its methods to accept parameters of less derived types than those specified in the interface.
source: https://msdn.microsoft.com/en-us/library/dd465120.aspx
You fix this by using the in and out keywords:
public interface IRepository<out T> : ...
(source: https://msdn.microsoft.com/en-us/library/dd997386.aspx)
Try this:
public class ServiceCodeController : ControllerBase {
// the red squiggly under IJobRepository is saying it's not convertible
private LazyRepo<IJobRepository, JobDomain> _domainRepo2;
}
public class LazyRepo<TRepo, TDomain> where TRepo : IRepository<TDomain> where TDomain : IDomainEntity { }
By specifying the TDomain as a generic parameter constrained to IDomainEntity and constraining TRepo to IRepository of TDomain, you provide all of the information needed by the compiler to resolve IJobRepository and JobDomain as arguments for LazyRepo. This provides an alternative to using variance.
The issue has to deal with the fact that IRepository<IDomainEntity> != IRepository<JobDomain>. It's the classic fruit bowl issue that's been discussed on SO. However, if you substitute a generic parameter for IDomainEntity, then you can fully qualify the run-time definition of TRepo for LazyRepo.
For completeness, here is a modified version of your code that compiles:
public class ControllerBase {}
public interface IDomainEntity {}
public interface IDomainEntityModifiable {}
public interface IDomainEntityActivatable {}
public interface IDomainEntityNameable {}
public interface IListRepository {}
public interface IRepositoryRead<out TDomain> where TDomain : IDomainEntity {}
public interface IRepositoryCreate<out TDomain> where TDomain : IDomainEntity {}
public interface IRepositoryDelete<out TDomain> where TDomain : IDomainEntity {}
public interface IRepositoryUpdate<out TDomain> where TDomain : IDomainEntity {}
public class ServiceCodeController : ControllerBase
{
private LazyRepo<IJobRepository, JobDomain> _domainRepo2;
}
public class LazyRepo<TRepo, TDomain> where TRepo : IRepository<TDomain> where TDomain : IDomainEntity { }
public interface IJobRepository : IRepository<JobDomain>, IListRepository { }
public interface IRepository<out T> : IRepositoryRead<T>,
IRepositoryCreate<T>,
IRepositoryDelete<T>,
IRepositoryUpdate<T>
where T : IDomainEntity { }
public class JobDomain : BaseDomainEntity { }
public abstract class BaseDomainEntity : IDomainEntity,
IDomainEntityModifiable,
IDomainEntityActivatable,
IDomainEntityNameable { }

C# Generic Covariance

I am getting error on DerivedFileInfo class declaration.
Error : The type 'StorageManager.Test.DerivedStorageProvider' cannot
be used as type parameter 'TStorageProvider' in the generic type or
method 'StorageManager.Test.BaseFileInfo'. There is no implicit
reference conversion from 'StorageManager.Test.DerivedStorageProvider'
to 'StorageManager.Test.IStorageProvider'.
Is there is something missing for generic constrains or I will require generic covariant?
public interface ICacheProvider
{
}
public class BaseCacheProvider : ICacheProvider
{
}
public class DerivedCacheProvider : BaseCacheProvider
{
}
public interface IStorageProvider<TCacheProvider> where TCacheProvider : ICacheProvider
{
}
public abstract class BaseStorageProvider<TCacheProvider> : IStorageProvider<TCacheProvider> where TCacheProvider : ICacheProvider
{
}
public class DerivedStorageProvider : BaseStorageProvider<DerivedCacheProvider>
{
}
public interface IResourceInfo<TStorageProvider> where TStorageProvider : IStorageProvider<ICacheProvider>
{
}
public abstract class ResourceInfo<TStorageProvider> : IResourceInfo<TStorageProvider>
where TStorageProvider : IStorageProvider<ICacheProvider>
{
}
public abstract class BaseFileInfo<TStorageProvider> : ResourceInfo<TStorageProvider> where TStorageProvider : IStorageProvider<ICacheProvider>
{
}
public class DerivedFileInfo : BaseFileInfo<DerivedStorageProvider>
{
}

Generic Interface Inheritance and Class Implementation for Repository Pattern

I have read a bit about constraints and am trying to implement it in my repository pattern.
I want something like the below but can't quite get it to compile.
public interface IRepository<T>
{
void GetAllData<T>();
}
//This needs to inherit from IRepository
//T has to be a model class
//V has to be a class that implements IEmployeeRepo
public interface IEmployeeRepo<T, V> where V : EmployeeRepo where T : class : IRepository<T>
{
void DoSomethingEmployeeRelated();
}
//Dont think this inheritance is correct
public class EmployeeRepo<Employee, this> : IEmployeeRepo
{
}
//My example model class
public class Employee
{
public string Name {get;set;}
}
Not sure why you have two type parameters on the Repository - what is the point?
*Here is the classic example of a .NET Repository using Generics: *
*First, the Repository Interface: *
public interface IRepository<T> where T : class
{
T FindSingle(Expression<Func<T,bool>> predicate);
IQueryable<T> FindAll(); // optional - matter of preference
void Add(T entity);
void Remove(T entity);
}
*Second, the Generic Repository Implementation (EF as the example): *
public abstract class GenericRepository<T> : IRepository<T>
{
private IObjectSet<T> _ObjectSet; // get this in via DI (for example)
public T FindSingle(Expression<T,bool>> predicate)
{
return _ObjectSet.SingleOrDefault(predicate);
}
// you can figure out how to do the other implementation methods
}
*Then, the Specific Repository (you should have one per aggregate root, and also an interface for each specific repository detailing specific methods): *
public EmployeeRepository : GenericRepository<Employee>, IRepository<Employee>
{
// all regular methods (Find, Add, Remove) inherited - make use of them
public Employee FindEmployeeByName(string name)
{
return FindAll().SingleOrDefault(x => x.Name == name);
// or you could do: return FindSingle(x => x.Name == name);
}
}
Usage:
IRepository<Employee> repository = new EmployeeRepository<Employee>();
Don't go out looking to go too crazy with generics - the only one you need is to constrain the Repository to be used by a entity that is encapsulated behind the Repository.
I simply use where T : class.
Other's use where T : IDomainAggregate or similar, to put constraints on the actual type of entity which is allowed.
In this situation i usually have a base repo class that implements IRepository<>, and is typed to a base Model class.
public interface IRepository<T> where T : IModel
{
void GetAll<T>();
void GetById<T>(int id);
}
public interface IEmployeeRepo<T> : IRepository<T> where T : IModel
{
void DoSomethingEmployeeRelated();
}
public class BaseRepo : IRepository<T> where T : IModel
{
public void GetAll<T>()
{
}
public void GetById<T>(int id)
{
}
}
public class EmployeeRepo : BaseRepo<Employee>, IEmployeeRepo<Employee>
{
public void DoSomethingEmployeeRelated()
{
}
}
//My example model class
public class Employee : IModel
{
public int Id {get;set;}
public string Name {get;set;}
}
Try this;
public interface IRepository<T>
{
void GetAllData<T>();
}
//This needs to inherit from IRepository
//T has to be a model class
//V has to be a class that implements IEmployeeRepo
public interface IEmployeeRepo<T, V> : IRepository<T> where V : EmployeeRepo where T : class
{
void DoSomethingEmployeeRelated();
}
//Dont think this inheritance is correct
public class EmployeeRepo : IEmployeeRepo<Employee, EmployeeRepo>
{
public void DoSomethingEmployeeRelated()
{
}
public void GetAllData<Employee>()
{
}
}
//My example model class
public class Employee
{
public string Name {get;set;}
}

Categories

Resources