I would like to do something like below in c#. Is there any trick to do it?
interface IGenericRepository<T> {
}
interface IModel<T>{
IGenericRepository<T> Repository { get; set; }
}
class ConcreteRepository : IGenericRepository<ConcreteModel>{
}
class ConcreteModel : IModel<ConcreteModel> {
ConcreteRepository Repository { get; set; } /// this doesn't work
/// IGenericRepository<ConcreateModel> Repository { get; set; } this would work
}
I fixed question.
CodePudding user response:
Please note, that since ConcreteModel
implements IModel<ConcreteModel>
then
ConcreteModel.Repository
must accept any class which implements IModel<ConcreteModel>
not necessary ConcreteRepository
,
i.e. the code below must be legal:
// Note, that MyOwnModel is not ConcreteModel
// But MyOwnModel implements IModel<ConcreteModel>
public class MyOwnModel : IModel<ConcreteModel> {
...
}
...
ConcreteModel demo = new();
// Must be valid, since MyOwnModel does implement Model<ConcreteModel>
demo.Repository = new MyOwnModel();
If you want to have ConcreteRepository Repository
while having IModel<ConcreteModel>
implemented you can implement the interface
explicitly:
class ConcreteModel : IModel<ConcreteModel> {
ConcreteRepository Repository { get; set; }
IGenericRepository<ConcreteModel> IModel<ConcreteModel>.Repository {
get => Repository;
set {
//TODO: you should do something if value IS NOT ConcreteRepository
// Here I've supposed that exception should be thrown
Repository = value is ConcreteRepository concrete
? concrete
: throw new ArgumentException("Value must be of ConcreteRepository type!");
}
}
}
CodePudding user response:
In short - no, this would not be type safe. Imagine if you could - then the following would be possible:
class ConcreteRepository1 : IGenericRepository<ConcreteModel>{}
IModel<ConcreteModel> x = new ConcreteModel();
x.Repository = new ConcreteRepository1(); // but ConcreteModel works only with `ConcreteRepository`
What you can do - remove setter from interface (so the code is still type safe and you don't need type checks) and explicitly implement it:
interface IModel<T>
{
IGenericRepository<T> Repository { get; }
}
class ConcreteModel : IModel<ConcreteModel>
{
public ConcreteRepository Repository { get; set; }
IGenericRepository<ConcreteModel> IModel<ConcreteModel>.Repository => Repository;
}