I found myself not following the DRY principle when I saw some copy pasted code. Pretty much
3x interfaces
3x classes
where the classes and interfaces where exactly the same.
Fine, remove the 2x interfaces and let the interface origin be only one as they are the same.
1x interface
3x classes
But since the classes did the exact same thing, I want to trim it down to
1x interface
1x classes
So the interface and class pretty much looks like
public class Foo : IFoo { }
Now that I want to register 3x difference instances of Foo as a singleton but with difference configurations, I get a compilation error. So my initial though was to have some marker interface for that, let's call them IBar , IBaz and IQux where all inherit from IFoo like:
public interface IBar : IFoo { }
public interface IBaz : IFoo { }
public interface IQux : IFoo { }
And register like:
services
.AddSingleton<IBar, Foo>(sp => /* configuration */)
.AddSingleton<IBaz, Foo>(sp => /* configuration */)
.AddSingleton<IQux, Foo>(sp => /* configuration */);
The compilation error I'm getting:
There is not implicit reference conversion from Foo to IBar.
Where am I going wrong?
Your marker interfaces inherit from IFoo and your class inherits from IFoo. Which means these four are just different implementations of IFoo. And you are trying to use Foo class as an implementation of IBar, IBaz, IQux which is not the case here.
Your Foo class should inherit from marker interfaces like so
public class Foo : IBar, IBaz, IQux { }
and then the following code should now work
services
.AddSingleton<IBar, Foo>(sp => /* configuration */)
.AddSingleton<IBaz, Foo>(sp => /* configuration */)
.AddSingleton<IQux, Foo>(sp => /* configuration */);
Related
I have multiple classes which extend a generic abstract base class:
public class BaseDetails {}
public class ADetails : BaseDetails {}
public class BDetails : BaseDetails {}
public abstract class Base<T> {}
public class A : Base<ADetails> {}
public class B : Base<BDetails> {}
This is all working, what I am struggling with is the dependency injection for registering many implementations of the generic abstract base class, so what I would like is:
IEnumerable<Base<BaseDetails>> _baseClasses;
I have tried to DI this like so but with no luck:
builder.RegisterMany(new[] { Assembly.Load(nameof(Program)) }, type => type.IsAssignableTo(typeof(Base<>)));
I feel like I am missing something on the DI side of things, any help is much appreciated!
Welcome to the world of covariance and contravariance. While IEnumerable<T> is covariant, your Base<T> class isn't, because classes can't have any variance applied to them. Only interfaces and delegates can. This means that the following code does not compile:
Base<BaseDetails> b = new A();
This code above is an important exercise to do, because when it comes to generics, DI Containers can easily cause you to be mislead in thinking that the problem is in the DI Container. Always try to reconstruct the problem by hand-wiring your object graphs without the use of the DI Container. For instance:
IEnumerable<Base<BaseDetails>> _baseClasses = new Base<BaseDetails>[]
{
new A(), // <- compile error here
new B(), // <- compile error here
};
Again, this code will not compile in C#:
CS0029 Cannot implicitly convert type 'A' to 'Base'
To make this work, you will have to change Base<T> to an interface and make its T generic argument covariant:
public interface Base<out T> { }
Something like this:
builder.RegisterMany(new[] { Assembly.Load(nameof(Program)) },
type => type.IsGeneric && type.GetGenericTypeDefinition() == typeof(Base<>)));
In the following sample class "SomeClass" does not implement "ISomeInterface". Why can't I implement this by passing a more derived interface which does implement the base requirement. Whatever instance would be passed it would still implement the base, am I missing something?
namespace Test
{
public interface IBaseInterface
{
void DoBaseStuff();
}
public interface IChildInterface : IBaseInterface
{
void DoChildStuff();
}
public interface ISomeInterface
{
void DoSomething(IBaseInterface baseInterface);
}
public class SomeClass : ISomeInterface
{
public void DoSomething(IChildInterface baseInterface)
{
}
}
}
This restriction exists because the ISomeInterface expects that any IBaseInterface will satisfy the contract. That is, if you have the following:
public interface IBase {}
public interface IChildA : IBase {}
public interface IChildB : IBase {}
And an interface that expects IBase:
public interface IFoo { void Bar(IBase val); }
Then restricting this in a derived class as you would like:
public class Foo : IFoo { public void Bar(IChildA val) {} }
Would create the following problem:
IChildB something = new ChildB();
IFoo something = new Foo();
something.Bar(something); // This is an invalid call
As such, you're not implementing the contract you said you would.
In this situation, you have two simple options:
Adjust IFoo to be generic, and accept a T that is a derivation of IBase:
public interface IFoo<T> where T : IBase { void Bar(T val); }
public class Foo : IFoo<IChildA> { public void Bar(IChildA val) {} }
Of course, this means that Foo can no longer accept any IBase (including IChildB).
Adjust Foo to implement IFoo, with an additional utility method for void Bar(IChildA val):
public class Foo : IFoo
{
public void Bar(IBase val) {}
public void Bar(IChildA val) {}
}
This has an interesting side-effect: whenever you call ((IFoo)foo).Bar it will expect IBase, and when you call foo.Bar it will expect IChildA or IBase. This means it satisfies the contract, while also having your derived-interface-specific method. If you want to "hide" the Bar(IBase) method more, you could implement IFoo explicitly:
void IFoo.Bar(IBase val) { }
This creates even more inconsistent behavior in your code, as now ((IFoo)foo).Bar is completely different from foo.Bar, but I leave the decision up to you.
This means, with the second version in this section, that foo.Bar(new ChildB()); is now invalid, as IChildB is not an IChildA.
Why can't I implement this by passing a more derived interface which does implement the base requirement. Whatever instance would be passed it would still implement the base, am I missing something?
This is not allowed because of the reasoning I mentioned above, IFoo.Bar expects any IBase, whereas you want to further constrain the type to IChildA, which is not a super-interface of IBase, and even if it were it would not be allowed because it violates the interface implementation, though you could more easily define a second method at that point that does what you want.
Keep in mind that when you implement an interface, you subscribe to a contract, and C# will not let you violate that contract.
This violates the Liskov substitution principle.
ISomeInterface guarantees that the method can be called with any IBaseInterface instance. Your implementation cannot limit that to only accept IChildInterface interfaces.
From MSDN:
When a class or struct implements an interface, the class or struct must provide an implementation for all of the members that the interface defines
This method in the derived
void DoSomething(IChildInterface baseInterface)
Does not have the same signature as the one in the interface:
void DoSomething(IBaseInterface baseInterface)
IChildInterface and IBaseInterface are not the same types. Therefore your derived class does not implement all methods of the interface and you get the compilation error.
For a possible the logic behind having this as a restriction instead of the compiler understanding the inheritance see Liskov's substitution principle as in SLakes answer
You should change some interface to use some type which implements IBaseInterface,
then change the method signatures to use whichever child your SomeClass wants.
public interface ISomeInterface<TSomeChild> where TSomeChild : IBaseInterface
{
void DoSomething(TSomeChild baseInterface);
}
public class SomeClass : ISomeInterface<IChildInterface>
{
public void DoSomething(IChildInterface baseInterface)
{
}
}
If you could do that, then you could do this:
IAnimal cat = new Cat();
IAnimalTrainer dogTrainer = new DogTrainer();
dogTrainer.Train(cat);
An IAnimalTrainer can train any IAnimal. But a DogTrainer can only train Dogs. Thus it's illegal for DogTrainer to implement the IAnimalTrainer interface.
Given an interface IFoo
interface IFoo {
void Do();
void Stuff();
}
Let assume there are (legacy) classes Foo1, Foo2, Foo3 all implementing IFoo.
Stuff can be done by using some methods of IFoo, or in case of the newer classes, by just using DoStuff(). Actually, one might look at it as if DoStuff() was "forgotten" on IFoo.
There are also newer Classes FooX (FooY, ...) implementing IFoo2, in additional those has a method DoStuff();
interface IFoo2 : IFoo {
void DoStuff();
}
I need to accept IFoo objects, and be able to "Do Stuff" on it.
//Let us assume foos = new IFoo[] {new Foo1(), new Foo2(), new Foo3(), new FooX()};
void MyMethod(IFoo[] foos){
foreach(foo in foos){
//DoStuff is not defined in IFoo
foo.DoStuff();
}
}
So, I thought to just define an extension method DoStuff() on IFoo for the legacy classes
public static DoStuff(this IFoo self){
self.Do();
self.Stuff();
}
Unfortunately, this extension method is always called, even for FooX.
I Could do something like
public static DoSomeStuff(this IFoo self){
if(self is IFoo2) {
(self as IFoo2).DoStuff()
} else {
self.Do();
self.Stuff();
}
}
void MyMethod(IFoo[] foos){
foreach(foo in foos){
foo.DoSomeStuff();
}
}
However, the method MyMethod reside in a legacy project, currently not yet aware of IFoo2. Is it possible to find a solution without using IFoo2?
You shouldn't extend IFoo interface, like that. It's break Interface Segregation principle.
If these object represents exactly the same entity in your code you shouldn't use different interfaces for them.
You might create extension method if you want extend functionality of classes which implements interface IFoo, but don't create second interface which represents the same contract. However if you want to change IFoo contract - refactor legacy objects (add missing implementation).
As long as your variable has the type IFoo, the extension method DoStuff will be called. The usual way of solving this is exactly what you propose in your last paragraph, or ensuring that you use IFoo2 instead of IFoo in places where you want the newer interface method to be called.
You can create an abstract subclass that implements the methods Do and Stuff for the classes that at the current time don't implement it.
public abstract class abstractFoo : IFoo
{
public virtual void Do() {}
public virtual void Stuff(){}
}
If you can then inherit from this abstract class
public class Foo: IFoo
{
// interface implementation required
}
becomes:
public class Foo: abstractFoo
{
// interface implementation NOT required
}
IMHO FooX shouldn't be implementing IFoo to begin with and some reconsideration should be made of your current arquitecture.
That said, and not knowing exactly what limitations you are fighting against, could you send the IFooXs through a wrapper? Something like the following:
public class FooXWrapper<T>: IFoo where T: FooX
{
readonly T foo;
bool doCalled;
public FooWrapper(T foo)
{
this.foo = foo;
}
public void Do()
{
doCalled = true;
}
public void Stuff()
{
if (!doCalled)
throw new InvalidOperationException("Must call Do");
foo.DoStuff();
}
}
Its an ugly hack, but given the circumstances...
I was wondering if there are any (runtime) difference if I implement an interface on a derived class if the base abstract class implements it already abstract:
public interface IFoo
{
void Bar();
}
public abstract class Base : IFoo
{
public abstract void Bar();
}
public class Derived : Base, IFoo // does this make any difference?
{
public override void Bar()
{
// do something
}
}
Is there any difference writing the "implemention" IFoo on Derived for example when I check if an instance implements an interface at runtime etc.?
Consider following on your example. Must the following be possible?
void f(Base b){
IFoo ifoo = b;
}
Because an object b is a Base, it must be an IFoo because Base implements IFoo. Now consider the following.
var d = new Derived();
f(d);
Since d is a Derived, it is a Base, because derived inherits from Base. Because of this, we can pass it to f, where it is then assigned to an IFoo, as we did before.
Essentially, because a derived class still is also all of its base classes, it already implements all of its base classes' interfaces. The designers of the language acknowledged this and there is no need to redeclare that a derived class is implementing interfaces that are implemented by its base classes.
I guess that maybe your question arises because of where you actually put the method body, but that really isn't relevant. The declaration of the interface is a contract for other consumers of objects of that type. Those consumers don't care where the method body was defined, all that they care is that when they have an IFoo, that it has a method with the signature void Bar() that can be called, as I showed earlier, inheritance must include all interfaces, so there is no need to declare them again.
The answer is No. There is no difference.
The Class Derived inherits from Base and Base in turn inherits from IFoo.
So, there is no necessity for you to "Implement" both Base and IFoo when defining the class Derived.
The hierarchy is established when you are defining the class Base:
public abstract class Base : IFoo
and continued when you define Derived as below:
public abstract class Derived : Base
The only problem may arise when you "Remove" Base from the hierarchy by redefining the Base class by removing the : IFoo implementation from the Base class definition as below:
public abstract class Base
The bottom line is: , IFoo is redundant and is therefore not necessary.
Is there any way in C# to have a generic type that is always the implementing type in an interface? Something like this:
interface Foo
{
this GetOtherThis();
}
class Bar : Foo
{
Bar GetOtherThis();
}
Is there any way in C# to have a generic type that is always the implementing type in an interface?
No. The answers given so far don't satisfy this, for two reasons:
You can always implement an interface with a different T
interface IFoo<T>
{
T GetOtherThis();
}
public class NotAString : Foo<string>
{
string GetOtherThis() { ... }
}
This can be fixed somewhere with a constraint: interface IFoo<T> where T : IFoo<T> but that still doesn't stop this;
public class Good : IFoo<Good> { ... }
public class Evil : IFoo<Good> { /* Mwahahahaha */ }
Inheritance breaks it anyway:
interface IFoo<T>
{
T GetOtherThis();
}
public class WellBehaved : IFoo<WellBehaved>
{
WellBehaved GetOtherThis() { ... }
}
public class BadlyBehaved : WellBehaved
{
// Ha! Now x.GetOtherThis().GetType() != x.GetType()
}
Basically there's nothing in C# which will enforce this for you. If you trust interface implementations to be sensible, then the generic interface scheme is still useful, but you need to understand its limitations.
Yes, you could write your code using a generic interface:
interface Foo<T>
{
T GetOtherThis();
}
class Bar : Foo<Bar>
{
Bar GetOtherThis();
}
Note: There is no generic constraint you can put on T to make T be the implementing class. Jon Skeet explains it much better detail.