In this post I talked about using a generic base class to enable me to create repository classes without duplicating loads of basic plumbing code.
Each Repository is accessed through an interface. In the code below, I will only show one of the methods for the sake of brevity:
Interface:
IQueryable<Suggestion> All { get; }
Generic base class
public IQueryable<T> All
{
get { return _unitOfWork.GetList<T>(); }
}
Concrete class (implements the interface and extends the generic base class)
public IQueryable<Suggestion> All
{
get { return _unitOfWork.GetList<Suggestion>(); }
}
I anticipated that I would be able to simply strip the method out of the concrete class, and the compiler would use the generic base class implementation instead and work out that was intended to satisfy the interface. But no!
When I strip the method out I get the old 'does not implement interface member' error.
If I can't do this, have my efforts to use a generic base class not been pointless? Or is there a way around this?
Can you make the interface itself generic then implement a typed version in your concrete class?
public interface IRepository<T>
{
List<T> All { get; }
}
public class Repository<T>
{
public List<T> All
{
get { return new List<T>(); }
}
}
public class SuggestionRepository : Repository<Suggestion>, IRepository<Suggestion>
{ }
I'd still suggest using the generic interface since it will save you from repeating yourself, but this works too.
public interface ISuggestionRepository
{
List<Suggestion> All { get; }
}
public class Repository<T>
{
public List<T> All
{
get { return new List<T>(); }
}
}
public class SuggestionRepository : Repository<Suggestion>, ISuggestionRepository
{ }
Use the virtual keyword and put your interface on your concrete implementation..
public interface IMyInterface<T>
{
IQueryable<T> All { get; }
}
public abstract class MyBaseClass<T> : IMyInterface<T>
{
public virtual IQueryable<T> All
{
get { return _unitOfWork.GetList<T>(); ; }
}
}
public class MyClass : MyBaseClass<Suggestion>, IMyInterface<Suggestion>
{
}
Related
I have an interface such as this one:
public interface ITestInterface
{
int a { get; set; }
void DoSomething();
}
Some of my classes are deriving from this interface:
public class OneClass : ITestInterface
{
public int a { get; set; }
public void DoSomething()
{
Console.WriteLine(this.a.ToString());
}
}
public class AnotherClass : ITestInterface
{
public int a { get; set; }
public void DoSomething()
{
Console.WriteLine((this.a * 2).ToString());
}
}
Since I now need a (large) common method on all classes derived from my interface, I was trying to provide an additional base class for that:
public class MyBaseClass
{
public void LargeCommonMethod()
{
Console.WriteLine((this.a * 3).ToString()); // no 'a' on base class
}
}
This clearly doesn't work because the base class would also need to implement my interface in order to know about that a field.
I am now asking myself what the best approach would be here:
make MyBaseClass inherit from ITestInterface?
set LargeCommonMethod() to protected and provide all internal data it uses via arguments? (There's actually a lot of these..)
skip the interface all along and replace it with an abstract base class?
...?
C# 8 provides a feature precisely for this scenario.
Your classes all implement an interface
You want to add a method to the interface
You don't want a breaking change to all of the existing classes. If you add a method to the interface all of the classes will break unless you find some way to add the method to all of them. (That includes modifying them all to inherit from a new base class.)
That feature is default interface methods.
You can add your method and a default implementation to the interface:
public interface ITestInterface
{
int a { get; set; }
void DoSomething();
void LargeCommonMethod()
{
Console.WriteLine((this.a * 3).ToString());
}
}
Your existing classes that implement the interface will not break. When cast as the interface, you'll be able to call the method which is defined in the interface. You can still modify any class to provide its own implementation, overriding the interface's default implementation.
For the method to be available the object must be cast as the interface - ITestInterface.
A lot of developers - including myself - found this to be an odd feature. But this is the scenario it's for.
Some documentation
The most common scenario is to safely add members to an interface already released and used by innumerable clients.
If you require a base implementation for a method then an interface is clearly not the way to go.
I would choose an abstract class instead and get rid of the interface. There is no need to complicate the design basically.
The Adapter pattern could fit your Use case, when you want to keep the ITestInterface consistent:
public interface ITestInterface
{
int a { get; set; }
void DoSomething();
}
public class TestInterfaceAdapter : ITestInterface
{
private readonly ITestInterface _testInterface;
public int a {
get => _testInterface.a;
set => _testInterface.a = value;
}
public TestInterfaceAdapter(ITestInterface testInterface)
{
_testInterface = testInterface;
}
public void DoSomething()
{
_testInterface.DoSomething();
}
public void LargeCommonMethod()
{
Console.WriteLine((this.a * 3).ToString());
}
}
public class OneClass : ITestInterface
{
public int a { get; set; }
public void DoSomething()
{
Console.WriteLine(this.a.ToString());
}
}
public class AnotherClass : ITestInterface
{
public int a { get; set; }
public void DoSomething()
{
Console.WriteLine((this.a * 2).ToString());
}
}
I may not be explaining this well, as I am not familiar with the vocabulary, but I have a base level interface, IMyStuff, that is inherited in a chain multiple times.
interface IOnceRemoved
{
IMyStuff MyStuff{get;set;}
}
interface ITwiceRemoved : IOnceRemoved
{
...
}
interface ITarget : ITwiceRemoved
{
...
}
public void MyMethod(ITarget target)
{
...
}
I have an object of the IMyStuff type. Is there a way to wrap this interface so MyMethod will accept it as an ITarget?
As Camilo already suggested, you need a wrapper like
class MyStuffAsTargetWrapper : ITarget
{
public MyStuffAsTargetWrapper(IMyStuff myStuff)
{
MyStuff = myStuff
}
public IMyStuff MyStuff{ get; set; }
}
and then call MyMethod(MyStuffAsTargetWrapper(myStuff)).
I'm trying to register a generic interface in Ninject, and then I want to some other interface to that generic interface:
public interface ISE<T> { }
public class SE<T> : ISE<T> { }
public interface IConcreteSE_A : ISE<SomeClass_A> { }
public interface IConcreteSE_B : ISE<SomeClass_B> { }
public interface IConcreteSE_C : ISE<SomeClass_C> { }
kernel.Bind(typeof(ISE<>)).To(typeof(SE<>));
kernel.Bind<IConcreteSE_A>().To(typeof(SE<>));
kernel.Bind<IConcreteSE_B>().To(typeof(SE<>));
kernel.Bind<IConcreteSE_C>().To(typeof(SE<>));
But I get an error: The number of generic arguments given is not equal to the number of general type definition arguments when I try to inject e.g. IConcreteSE_A to my web api controller.
how to fix it ?
This is because there is no implicit reference conversion between IConcreteSE_A and ISE<SomeClass_A>. In other words there is no guarantee that SE<SomeClass_A>, which implements ISE<SomeClass_A>, actually satisfies the implementation for IConcreteSE_A.
You can fix this by creating a concrete class that implements both interfaces and then bind to that.
public class SE<T> : ISE<T> { }
public class SomeClassA { }
public class ConcreteSE_A : ISE<SomeClass_A>, IConcreteSE_A { }
public interface IConcreteSE_A : ISE<SomeClass_A> { }
kernel.Bind(typeof(ISE<>)).To(typeof(SE<>));
kernel.Bind<IConcreteSE_A>().To<ConcreteSE_A>();
I have a design issue and am looking for the best design solution. I have added an example of the issue below.
public interface IVehicle<T>
{
int GetEngineSize();
}
public class Car : IVehicle<Car>
{
public int GetEngineSize()
{
throw new NotImplementedException();
}
public bool HasSpolier()
{
return true;
}
}
public class Bus : IVehicle<Bus>
{
public int GetEngineSize()
{
throw new NotImplementedException();
}
}
public abstract class BaseController<T>
{
public IVehicle<T> Repository { get; set; }
}
public abstract class CarController : BaseController<Car>
{
public CarController()
{
// How can I access the HasSpolier method from the IVehicle<T> without having to cast the Interface to concrete class Car
bool result = Repository.HasSpolier();
}
}
I'm not sure your generics are doing what you want here.
If instead of
IVehicle<T> Repository {get; set;}
You did
T Repository {get; set;}
You could make
public abstract class BaseController<T> where T : IVehicle
To ensure that they're of the IVehicle Interface
Then you'd have a typed repository and get access to your spoiler method.
You're doing IVehicle<Bus> but at least in the sample code, the T is never used in the interface. At this point the T is worthless.
Unless you implement the method in the interface, you can't access it without casting it to another class.
You'd have to cast your Repository to Car.
It would make using your interface pointless as the dependency on the implementation which you're trying to remove is re-introduced.
Also the type parameter on your interface isn't required, you don't use it anywhere else in the interface...
public interface IVehicle
{
int GetEngineSize();
}
Why isn't this working ?
public interface IPoint
{
// not important
}
public interface IPointList
{
List<IPoint> Points { get; }
}
public abstract class Point : IPoint
{
// implemented IPoint
}
public abstract class PointList<TPointType> : IPointList
where TPointType: IPoint
{
public abstract List<TPointType> Points { get; } // <- doesn't compile
}
The TPointType obviously has to be an IPoint. Why this implementation is not allowed ?
regards,
Kate
As an answer to your comment, on how to get best of both worlds;
I was thinking of something like this, where you implement your interface GetPoints property explictily, create a GetPoints property that is 'more typed', and an protected abstract method that you can override in concrete implementations.
The 2 properties call the abstract implementation.
public abstract class PointList<T> : IPointList where T : IPoint
{
public IList<T> GetPoints
{
get
{
return GetPointsCore ();
}
}
IList<IPoint> IPointList.GetPoints
{
get
{
return GetPointsCore () as IList<IPoint>;
}
}
protected abstract IList<T> GetPointsCore();
}
The class PointList should implement the IPointList interface. Methods/properties cannot differ by return type only, which is what you're trying to do with the Points declaration in class PointList. If you implement
List<TPointType> Points { get; }
then logically you cannot implement
List<IPoint> Points { get; }
Because they would differ by return type only.