How to reuse generic interface? - c#

I'm using ASP.NET Boilerplate, on ASP.NET Core.
I have some model classes.
public class AClass : FullAuditedEntity<int>
{
}
and one interface like below.
public interface ISomeInterface<T, TEntity> where T : BaseFileEntity where TEntity : class, IEntity<int>
{
}
Now If I add one extra model class like below.
public class BClass : FullAuditedEntity<string>
{
}
I have to define another interface for this change like below.
public interface ISomeInterface<T, TEntity> where T : BaseFileEntity where TEntity : class, IEntity<string>
{
}
So basically it's duplicate code. Is there any better way to do this?

Is it possible to declare your interface like the one below so you can pass the type to IEntity
public interface ISomeInterfaceB<T, TEntity, TK> where T : BaseFileEntity where TEntity : class, IEntity<TK> {
}

You can Change the interface to:
public interface ISomeInterface<T, TEntity, U> where T : BaseFileEntity where TEntity : class, IEntity<U>
{
}

Related

Passing type parameter to interface of base class

StateBase implements iState
WolfState ineherits from StateBase
WolfController inherits from ControllerBase
I want to be able to do a
WolfState that uses WolfController inheriting from State
SheepState
that uses SheepController and inherits from State
WolfController and SheepController would both inherit from StateController.
How should i declare WolfState?
The way i try to do it doesnt work.
public interface IState <T> where T : StateController
{
}
public abstract class State<T> where T : StateController, IState<T>
{
}
// THIS IS HOW I WOULD LIKE TO DO IT BUT ITS NOT ACCEPTED
public class WolfState : State<WolfController>
{
}
public class SheepState : State<SheepController>
{
}
It looks like you intend State<T> to implement IState<T>. You currently have a constraint on the type of T. Change the definition of State<T> to:
public abstract class State<T> : IState<T> where T : StateController
{
}

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 { }

How to specify type constraint and inheritance on declaring class?

I've got an abstract class which has a type constraint. But i also want to make the abstract class implement an interface.
E.g:
public abstract class PostEvent<TPost> : IDomainEvent, where TPost : Post, new()
Which doesn't compile.
I don't want this:
public abstract class PostEvent<TPost> where TPost : Post, IDomainEvent, new()
Because that means TPost : IDomainEvent
I want PostEvent : IDomainEvent
What's the syntax?
Try this:
public abstract class PostEvent<TPost> : IDomainEvent where TPost : Post, new()
You don't want a comma between the interface list and the generic constraints.
You need to actually implement it (you can't leave the implementation purely to the concrete types - it needs to know where to start):
public abstract class PostEvent<TPost> : IDomainEvent
where TPost : Post, new()
{
public abstract void SomeInterfaceMethod();
}
You could also use an explicit interface implementation and protected abstract method if you don't want Otis on the public API:
public abstract class PostEvent<TPost> : IDomainEvent
where TPost : Post, new()
{
protected abstract void SomeInterfaceMethod();
void IDomainEvent.SomeInterfaceMethod() {
SomeInterfaceMethod(); // proxy to the protected abstract version
}
}

C# Generic Repository

I am trying to implement a generic repository but I am snagged. Here is a summary of my object model. The problem is that the concrete repository, "UserAccountRepositoryStub" will not compile. The error is:
The type User has to be convertible to type IRepository...
IRepostory:
public interface IRepository<T> where T : IEntity
{
...
}
Abstract Repository:
public class AbstractRepository<T> where T : class, IEntity, IRepository<T> {...}
IUserAccountRepository:
public interface IUserAccountRepository
User:
public class User : IEntity{...}
UserRepositoryStub(concrete):
public class UserAccoutRepositoryStub : AbstractRepository<User>, IUserAccountRepository
The definition of AbstractRepository<T> should probably be
public class AbstractRepository<T> : IRepository<T> where T : class, IEntity {...}
because you want the repository to implement IRepository<T> not the objects in it, right?
Your AbstractRepository requires that T is of type IRepository<T>. Did you mean to do:
public class AbstractRepository<T> : IRepository<T> where T : class, IEntity, {...}
On your AbstractRepository you've got the IRepository in the wrong spot. Everything after the "where" and before the "{...}" specifies the generic constraints. To specify inheritence you need to put it before the where.
Try this instead
public class AbstractRepository<T> : IRepository<T> where T : class, IEntity {...}

Categories

Resources