Inherited Generic Type Unification - c#

For a scenario such as this:
public interface IAnimal
{
}
public interface IGiraffe : IAnimal
{
}
public interface IQuestionableCollection : IEnumerable<IAnimal>
{
void SomeAction();
}
public interface IQuestionableCollection<out T> : IQuestionableCollection, IEnumerable<T>
where T : IAnimal
{
}
public class QuestionableCollection<T> : IQuestionableCollection<T>
where T:IAnimal
{
// Implementation...
}
The complier will generate an error:
'IQuestionableCollection<T>' cannot implement both 'System.Collections.Generic.IEnumerable<IAnimal>' and 'System.Collections.Generic.IEnumerable<T>' because they may unify for some type parameter substitutions
And that makes sense, there is indeed an ambiguity between the two interfaces which C# can't resolve unless it uses the type constraint, which it doesn't per the language spec as #ericlippert explains here.
My question is how should I implement something to the same effect here?
It seems like I should be able to express that the collection is enumerable for the base interface. (I'd like to provide a set of methods that could be utilized without knowing the concrete type, as well as it make some APIs/reflection code cleaner, so I'd like to keep the base collection as non-generic if at all possible. Otherwise, there would be no need for two interfaces.)
The only implementation I can think of that compiles is something like:
public interface IQuestionableCollectionBase
{
void SomeAction();
}
public interface IQuestionableCollection : IQuestionableCollectionBase, IEnumerable<IAnimal>
{
}
public interface IQuestionableCollection<out T> : IQuestionableCollectionBase, IEnumerable<T>
where T : IAnimal
{
}
public class QuestionableCollectionBase<T> : IQuestionableCollection
where T : IAnimal
{
protected List<T> _items = new List<T>();
public void SomeAction() { }
IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)_items).GetEnumerator(); }
IEnumerator<IAnimal> IEnumerable<IAnimal>.GetEnumerator() { return ((IEnumerable<IAnimal>)_items).GetEnumerator(); }
}
public class QuestionableCollection<T> : QuestionableCollectionBase<T>, IQuestionableCollection<T>
where T : IAnimal
{
public IEnumerator<T> GetEnumerator() { return ((IEnumerable<T>)_items).GetEnumerator(); }
}
Note that I've had to move any methods I'd like to use on both interfaces to a base method and have two levels of implementation for the class itself - which seems like I'm jumping through enough hoops here that I've got to be missing something...
How should this be implemented?

The simplest workaround is to change the IEnumerables from "is-a" to "has-a", like this:
public interface IAnimal { }
public interface IGiraffe : IAnimal { }
public interface IQuestionableCollection
{
IEnumerable<IAnimal> Animals { get; }
void SomeAction();
}
public interface IQuestionableCollection<out T> : IQuestionableCollection
where T : IAnimal
{
new IEnumerable<T> Animals { get; }
}
public class QuestionableCollection<T> : IQuestionableCollection<T>
where T : IAnimal, new()
{
private readonly List<T> list = new List<T>();
public IEnumerable<T> Animals
{
get { return list; }
}
IEnumerable<IAnimal> IQuestionableCollection.Animals
{
get { return (IEnumerable<IAnimal>)list; }
}
public void SomeAction()
{
list.Add(new T());
}
}
class Giraffe : IGiraffe { }
[TestMethod]
public void test()
{
var c = new QuestionableCollection<Giraffe>();
IQuestionableCollection<Giraffe> i = c;
IQuestionableCollection<IGiraffe> i2 = i;
Assert.AreEqual(0, c.Animals.Count());
Assert.AreEqual(0, i.Animals.Count());
c.SomeAction();
i.SomeAction();
Assert.AreEqual(2, c.Animals.Count());
Assert.AreEqual(2, i.Animals.Count());
}
Note that you can avoid the cast in QuestionableCollection<T> if you add a where T : class constraint.

Changing IQuestionableCollection to a non-generic IEnumerable sorts the compiler issues.
public interface IQuestionableCollection : IEnumerable {...}
I've seen MS use this pattern in their collections, with the non-generic versions using IEnumerable, and the generic ones using IEnumerable<T>.
Alternatively, making the others IEnumerable<IAnimal> also stops the compiler errors, though it means you get IAnimals back instead of T's when enumerating.

You could try this:
public interface IAnimal
{
}
public interface IGiraffe : IAnimal
{
}
public interface IQuestionableCollection<T> : IEnumerable<T> where T : IAnimal
{
void SomeAction();
}
public interface IQuestionableCollection : IQuestionableCollection<IAnimal>
{
}
public class QuestionableCollection<T> : IQuestionableCollection<T>, IEnumerable<T>
where T : IAnimal
{
public void SomeAction() { }
public IEnumerator<T> GetEnumerator()
{
throw new NotImplementedException();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
}

Given the constraints of the language you won't be able to work around the problem of having IQuestionableCollection and IQuestionableCollection both implementing a Generic Interface.
In essence what you are specifying is that IQuestionableCollection implements two possible lists, List and another List. There is no hierarchical relationship here so it impossible to resolve.
That being said you would have to replace IEnumerable with IEnumerable on IQuestionableCollection to provide an inheritance chain to the compiler. In reality there isn't really even a point to declaring the base IQuestionableCollection unless you plan on implementing a vanilla QuestionableCollection
In my updated code I took it out to a consumer of QuestionableCollection to illustrate the enumeration of QuestionableCollection() retains the typing of IGiraffe.
public interface IAnimal {}
public interface IGiraffe : IAnimal { }
public interface IQuestionableCollection : IEnumerable
{
void SomeAction();
}
public interface IQuestionableCollection<out T> : IQuestionableCollection, IEnumerable<T>
where T : IAnimal
{ }
public class QuestionableCollection<T> : IQuestionableCollection<T>
where T : IAnimal
{
private List<T> list = new List<T>();
public IEnumerator<T> GetEnumerator()
{
return list.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void SomeAction()
{
throw new NotImplementedException();
}
}
class Program
{
static void Main(string[] args)
{
var questionable = new QuestionableCollection<IGiraffe>();
foreach (IGiraffe giraffe in questionable)
{
}
}
}
For the Non Generic Implementation
1 You can always safely upcast
var questionable = new QuestionableCollection();
IEnumerabl<IAnimal> animals = questionable.OfType<IAnimal>();
-or-
2 You can have the NonGeneric QuestionableCollection class implement IEnumerable
public class QuestionableCollection : IQuestionableCollection, IEnumerable<IAnimal>
{
public IEnumerator<IAnimal> GetEnumerator()
{
var l = new List<Giraffe>();
l.Add(new Giraffe());
l.Add(new Giraffe());
return l.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void SomeAction()
{
throw new NotImplementedException();
}
}
Which you then can enumerate without a cast operation.
var questionable = new QuestionableCollection();
foreach (IAnimal giraffe in questionable)
{
var i = giraffe;
}

Related

Can't convert interface to concrete interface

Why i can't convert implementation of interface which concrete implement generic interface? I need for Cat, Dog etc own interface realisation.
public interface IMarker { }
public class ResultA : IMarker
{
}
public class ResultB : IMarker
{ }
public interface IService<T> where T : IMarker
{
public List<T> DoStuff();
}
public interface ICatService : IService<ResultA>
{ }
public interface IDogService : IService<ResultB>
{ }
public class CatService : ICatService
{
public List<ResultA> DoStuff()
{
return new List<ResultA>();
}
}
public class DogService : IDogService
{
public List<ResultB> DoStuff()
{
return new List<ResultB>();
}
}
public abstract class Animal
{
protected readonly IService<IMarker> _svc;
protected Animal(IService<IMarker> svc)
{
_svc = svc;
}
}
public class Cat : Animal
{
public Cat(ICatService svc) : base(svc)
{
}
}
public class Dog : Animal
{
public Dog(ICatService svc) : base(svc)
{
}
}
CS1503 Argument 2: cannot convert from 'ICatService' to 'IService'
I have DI for services i.e. :
services.AddTransient<ICatService, CatService>();
The reason for such behaviour is that in general case IService<ResultA> is not IService<IMarker> (basically I would argue the same cause for C# classes does not supporting variance which is for a pretty good reason - see more here and here).
In this concrete case everything can be fixed by making the interface covariant and leveraging the covariance of IEnumerable<T>:
public interface IService<out T> where T : IMarker
{
public IEnumerable<T> DoStuff();
}
public class CatService : ICatService
{
public IEnumerable<ResultA> DoStuff() => return new List<ResultA>();
}
public class Cat : Animal
{
public Cat(CatService svc) : base(svc)
{
}
}
But not sure that in your actual code you will be able to.
Or just make the base class generic (if this suits your use case):
public abstract class Animal<T> where T : IMarker
{
protected readonly IService<T> _svc;
protected Animal(IService<T> svc)
{
_svc = svc;
}
}
Original answer
CatService does not implement ICatService, i.e. the fact that ICatService inherits only IService<ResultA> does not mean that they are the same, C# is strongly-typed (mostly :-) language and compiler will consider those two interfaces being different ones (though related). You need either to make CatService to implement ICatService:
public class CatService : ICatService
{
// ...
}
Or register and resolve the IService<ResultA> interface (basically skipping intermediate interface at all):
services.AddTransient<IService<ResultA>, CatService>();
// ...
public Cat(IService<ResultA> svc) : base(svc){}

Avoid explicit type casting when overriding inherited methods

I have a base abstract class that also implements a particular interface.
public interface IMovable<TEntity, T>
where TEntity: class
where T: struct
{
TEntity Move(IMover<T> moverProvider);
}
public abstract class Animal : IMovable<Animal, int>
{
...
public virtual Animal Move(IMover<int> moverProvider)
{
// performs movement using provided mover
}
}
Then I have inherited classes some of which have to override interface implementation methods of the base class.
public class Snake : Animal
{
...
public override Animal Move(IMover<int> moverProvider)
{
// perform different movement
}
}
My interface methods return the same object instance after it's moved so I can use chaining or do something directly in return statement without using additional variables.
// I don't want this if methods would be void typed
var s = GetMySnake();
s.Move(provider);
return s;
// I don't want this either if at all possible
return (Snake)GetMySnake().Move(provider);
// I simply want this
return GetMySnake().Move(provider);
Question
As you can see in my example my overrides in child class returns base class type instead of running class. This may require me to cast results, which I'd like to avoid.
How can I define my interface and implementations so that my overrides will return the actual type of the executing instance?
public Snake Move(IMover<int> moverProvider) {}
I suggest changing the return type of the interface method to void and moving the chaining behaviour to an extension method where you can get the real type of the target e.g.
public interface IMovable<TEntity, T>
where TEntity : class
where T : struct
{
void MoveTo(IMover<T> moverProvider);
}
public abstract class Animal : IMovable<Animal, int>
{
public virtual void MoveTo(IMover<int> mover) { }
}
public static class AnimalExtensions
{
public static TAnimal Move<TAnimal>(this TAnimal animal, IMover<int> mover) where TAnimal : Animal, IMovable<TAnimal, int>
{
animal.MoveTo(mover);
return animal;
}
}
Note you can make the Move extension more generic if you need it to apply more generally:
public static TEntity Move<TEntity, T>(this TEntity entity, IMover<T> mover) where TEntity : IMovable<TEntity, T> where T : struct
{
entity.MoveTo(mover);
return entity;
}
You can convert Animal to a generic type that accepts the concrete type as a type parameter:
public abstract class Animal<T> : IMovable<T, int> where T:Animal<T>
{
public virtual T Move(IMover<int> moverProvider)
{
...
}
}
public class Snake : Animal<Snake>
{
public override Snake Move(IMover<int> moverProvider)
{
...
}
}
How about:
public virtual T Move<T>(IMover<int> moverProvider) where T : Animal
{
// performs movement using provided mover
}
Sometimes you need to have current type as method return value and it has to change in derived classes. I'd avoid this pattern because it'll lead to strange behaviors and unusual syntax (if your model becomes complex) but give it a try (primary because for very small hierarchies it looks pretty simple):
abstract class Animal<TConcrete> : IMovable<TConcrete, int>
where TConcrete : Animal<T>
{
public virtual T Move(IMover<int> moverProvider) {
return (T)this; // Cast to Animal<T> to T isn't implicit
}
}
sealed class Snake : Animal<Snake>
{
public virtual Snake Move(IMover<int> moverProvider) {
return this;
}
}
Why is this bad? You can answer yourself when you'll need to declare a generic variable of type Animal<TConcrete> (in practice this stops you to have a variable with that base class).
What I'd do is to make this requirement clear (with a class or an extension method - in this case using another name):
abstract class Animal : IMovable<Animal, int>
{
// Please note that this implementation is explicit
Animal IMovable<Animal, int>.Move(IMover<int> moverProvider) {
return MoveThisAnimal(moverProvider);
}
protected virtual Animal MoveThisAnimal(IMover<int> moverProvider) {
// Peform moving
return this;
}
}
class Snake : Animal
{
public Snake Move(IMover<int> moverProvider) {
return (Snake)MoveThisAnimal(moverProvider);
}
protected override Animal MoveThisAnimal(IMover<int> moverProvider) {
// Peform custom snake moving
return this;
}
}
It's messy, but by introducing a non-generic base interface, an extension method can give the desired result. It can also be simplified (to remove the second explicit interface implementation) if you don't care about exposing the 'MoveFunc' to callers:
public interface IMovable
{
IMovable MoveFunc();
}
public interface IMovable<TEntity, T> : IMovable
where TEntity : IMovable
{
new TEntity MoveFunc();
}
public abstract class Animal : IMovable<Animal, int>
{
protected virtual Animal MoveFunc()
{
// performs movement using provided mover
Debug.WriteLine("Animal");
}
Animal IMovable<Animal, int>.MoveFunc()
{
return MoveFunc();
}
IMovable IMovable.MoveFunc()
{
return ((IMovable<Animal, int>)this).MoveFunc();
}
}
public class Snake : Animal
{
protected override Animal MoveFunc()
{
// performs movement using provided mover
Debug.WriteLine("Snake");
}
}
public static class IMovableExtensions
{
public static TOut Move<TOut>(this TOut entity) where TOut : IMovable
{
return (TOut)entity.MoveFunc();
}
}
...
Snake snake = new Snake();
Snake moved = snake.Move(); // "Snake"
Animal animal = snake;
animal.Move() // "Snake"

C# Generics: wildcards

I'm new to the c# world, and I'm trying to wrap my head around generics. Here is my current problem:
public Interface IAnimal{
string getType();
}
public Interface IAnimalGroomer<T> where T:IAnimal{
void groom(T);
}
Now I want to have a dictionary that contains these animal groomers. How do I do that? In java, I could do something like this:
HashMap<String,IAnimalGroomer<?>> groomers = new HashMap<>();
Edit: Here is an example of what I'm trying to do:
public class Dog : IAnimal
{
public string GetType()
{
return "DOG";
}
public void ClipNails() { }
}
public class DogGroomer : IAnimalGroomer<Dog>
{
public void Groom(Dog dog)
{
dog.ClipNails();
}
}
public class Program
{
private List<IAnimalGroomer<IAnimal>> groomers = new List<IAnimalGroomer<IAnimal>>();
public void doSomething()
{
//THIS DOESN"T COMPILE!!!!
groomers.Add(new DogGroomer());
}
}
EDIT
I think my intentions were unclear in the original post. My ultimate goal is to make an AnimalGroomerClinic that employs different types of IAnimalGroomers. Then animal owners can drop off animals at the clinic, and the clinic can decide which groomer should take care of the animal:
public class AnimalGroomerClinic
{
public Dictionary<String, IAnimalGroomer> animalGroomers = new Dictionary<String,IAnimalGroomer>();
public void employGroomer(IAnimalGroomer groomer){
animalGroomers.add(groomer.getAnimalType(), groomer);
}
public void Groom(IAnimal animal){
animalGroomers[animal.getAnimalType()].Groom(animal);
}
}
I realize I could do this without using generics. But the generics allow me to write the IAnimalGroomer interface in such a way that it is tied (at compile time) to a specific instance of IAnimal. In addition, concrete classes of IAnimalGroomer don't need to cast their IAnimals all the time, since generics would force implementations to deal with one specific kind of animal. I have used this idiom before in Java, and I'm just wondering if there is a similar way to write it in C#.
Edit 2:
Lots of interesting discussion. I'm accepting an answer that pointed me to dynamic dispatching in the comments.
What you want is call site covariance, which is not a feature that C# supports. C# 4 and above support generic variance, but not call site variance.
However, that doesn't help you here. You want a dog groomer to be put in a list of animal groomers, but that can't work in C#. A dog groomer cannot be used in any context in which an animal groomer is needed because a dog groomer can only groom dogs but an animal groomer can also groom cats. That is, you want the interface to be covariant when it cannot be safely used in a covariant manner.
However your IAnimalGroomer<T> interface could be contravariant as it stands: an animal groomer can be used in a context in which a dog groomer is required, because an animal groomer can groom dogs. If you made IAnimalGroomer<T> contravariant by adding in to the declaration of T then you could put an IAnimalGroomer<IAnimal> into an IList<IAnimalGroomer<Dog>>.
For a more realistic example, think of IEnumerable<T> vs IComparer<T>. A sequence of dogs may be used as a sequence of animals; IEnumerable<T> is covariant. But a sequence of animals may not be used as a sequence of dogs; there could be a tiger in there.
By contrast, a comparer that compares animals may be used as a comparer of dogs; IComparer<T> is contravariant. But a comparer of dogs may not be used to compare animals; someone could try to compare two cats.
If that is still not clear then start by reading the FAQ:
http://blogs.msdn.com/b/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx
and then come back and ask more questions if you have them.
There are two interfaces, IEnumerable and IEnumerable<T> which are close to what you are trying to accomplish. So you can have a dictionary like Dictionary<string,IEnumerable> which can contain as values IEnumerable<int>, IEnumerable<string>, etc. The trick here is to derive IAnimalGroomer<T> from IAnimalGroomer, a non generic interface.
EDIT:
As an example, per your request, after creating an interface called IAnimalGroomer with:
public interface IAnimalGroomer{
}
, if you change the line that reads:
public interface IAnimalGroomer<T> where T:IAnimal{
to
public interface IAnimalGroomer<T> : IAnimalGroomer where T:IAnimal{
and the line that reads:
private List<IAnimalGroomer<IAnimal>> groomers = new List<IAnimalGroomer<IAnimal>>();
to
private List<IAnimalGroomer> groomers=new List<IAnimalGroomer>();
your code should compile and work.
I know this has been Lipperted but I still feel like answering. The List is a red herring here, it doesn't matter that you're using it.
The reason this doesn't work is because IAnimalGroomer<T> itself is not covariant, and it can't be made covariant explicitly because of the groom(T) method. It is illegal to cast IA<Derived> to IA<Base> in the general case, or in different words, generic interfaces are not covariant by default. The List<T>.Add method is what triggers a cast from DogGroomer (which is IAnimalGroomer<Dog>) to IAnimalGroomer<IAnimal>, but for example, this still won't work:
IAnimalGroomer<Dog> doggroomer = new DogGroomer(); // fine
IAnimalGroomer<IAnimal> animalgroomer = doggroomer; // invalid cast, you can explicitly cast it
// in which case it fails at run time
If this worked (so if IAnimalGroomer<T> was covariant), you could in fact also add a DogGroomer to your list, despite the List<T> not being covariant! That's why I said the list is a red herring.
The reason generic interface covariance isn't the default is because of type safety. I added Cat/CatGroomer classes to your code that are basically the same as the ones for dogs. Look at the main function and the comments in it.
public interface IAnimal
{
string getType();
}
public interface IAnimalGroomer<T> where T:IAnimal
{
void groom(T t);
}
public class Dog : IAnimal
{
public string getType() { return "DOG"; }
public void clipNails() { }
}
public class DogGroomer : IAnimalGroomer<Dog>
{
public void groom(Dog dog)
{
dog.clipNails();
}
}
public class Cat : IAnimal
{
public string getType() { return "CAT"; }
public void clipNails() { }
}
public class CatGroomer : IAnimalGroomer<Cat>
{
public void groom(Cat cat)
{
cat.clipNails();
}
}
public class Program
{
static void Main(string[] args)
{
// this is fine.
IAnimalGroomer<Dog> doggroomer = new DogGroomer();
// this is an invalid cast, but let's imagine we allow it!
IAnimalGroomer<IAnimal> animalgroomer = doggroomer;
// compile time, groom parameter must be IAnimal, so the following is legal, as Cat is IAnimal
// but at run time, the groom method the object has is groom(Dog dog) and we're passing a cat! we lost compile-time type-safety.
animalgroomer.groom(new Cat());
}
}
There are no sequences used, yet the code would still break type safety if it was legal.
This type of cast could be allowed, but the errors caused by it would happen at run-time, which I imagine was not desirable.
If you mark the type parameter T as "out", then you can cast A<Derived> into A<Base>. However, you can no longer have a method with T as an argument, which you do. But it eliminates the problem of trying to shove a Cat into a Dog.
IEnumerable<T> is an example of a covariant interface - it has no f(T) methods so the problem can't happen, unlike with your groom(T) method.
As Brian pointed out in comments above, maybe dynamic is the way to go here.
Check out the following code. You get the benefits of generics to tie down the API nicely and under the hoods you use dynamic to make things work.
public interface IAnimal
{
}
public class Dog : IAnimal
{
}
public class Cat : IAnimal
{
}
public class BigBadWolf : IAnimal
{
}
//I changed `IAnimalGroomer` to an abstract class so you don't have to implement the `AnimalType` property all the time.
public abstract class AnimalGroomer<T> where T:IAnimal
{
public Type AnimalType { get { return typeof(T); } }
public abstract void Groom(T animal);
}
public class CatGroomer : AnimalGroomer<Cat>
{
public override void Groom(Cat animal)
{
Console.WriteLine("{0} groomed by {1}", animal.GetType(), this.GetType());
}
}
public class DogGroomer : AnimalGroomer<Dog>
{
public override void Groom(Dog animal)
{
Console.WriteLine("{0} groomed by {1}", animal.GetType(), this.GetType());
}
}
public class AnimalClinic
{
private Dictionary<Type, dynamic> groomers = new Dictionary<Type, dynamic>();
public void EmployGroomer<T>(AnimalGroomer<T> groomer) where T:IAnimal
{
groomers.Add(groomer.AnimalType, groomer);
}
public void Groom(IAnimal animal)
{
dynamic groomer;
groomers.TryGetValue(animal.GetType(), out groomer);
if (groomer != null)
groomer.Groom((dynamic)animal);
else
Console.WriteLine("Sorry, no groomer available for your {0}", animal.GetType());
}
}
And now you can do:
var animalClinic = new AnimalClinic();
animalClinic.EmployGroomer(new DogGroomer());
animalClinic.EmployGroomer(new CatGroomer());
animalClinic.Groom(new Dog());
animalClinic.Groom(new Cat());
animalClinic.Groom(new BigBadWolf());
I'm not sure if this is somewhat what you were looking for. Hope it helps!
Here is some code that works. I've added some classes and switch AnimalGroomer to be an abstract class not an interface:
class Program
{
static void Main(string[] args)
{
var dict = new Dictionary<string, IGroomer>();
dict.Add("Dog", new DogGroomer());
// use it
IAnimal fido = new Dog();
IGroomer sample = dict["Dog"];
sample.Groom(fido);
Console.WriteLine("Done");
Console.ReadLine();
}
}
// actual implementation
public class Dog : IAnimal { }
public class DogGroomer : AnimalGroomer<Dog>
{
public override void Groom(Dog beast)
{
Console.WriteLine("Shave the beast");
}
}
public interface IAnimal {
}
public interface IGroomer
{
void Groom(object it);
}
public abstract class AnimalGroomer<T> : IGroomer where T : class, IAnimal
{
public abstract void Groom(T beast);
public void Groom(object it)
{
if (it is T)
{
this.Groom(it as T);
return;
}
throw new ArgumentException("The argument is not a " + typeof(T).GetType().Name);
}
}
Please let me know if there are any questions
From my understanding, you cannot put the type constraints in the parameter in this case. which means you might need to do the boxing and unboxing. you might need to use a normal interface.
public interface IAnimal{
string GetType();
}
public interface IAnimalGroomer{
void Groom(IAnimal dog);
}
public class Dog : IAnimal
{
public string GetType()
{
return "DOG";
}
public void ClipNails()
{
}
}
public class DogGroomer : IAnimalGroomer
{
public void Groom(IAnimal dog)
{
if (dog is Dog)
{
(dog as Dog).ClipNails();
}
else {
// something you want handle.
}
}
}
public class Program
{
private List<IAnimalGroomer> groomers = new List<IAnimalGroomer>();
public void doSomething()
{
groomers.Add(new DogGroomer());
}
}
Or maybe you need to have another technical design for solving your problem
I'm adversed to using dynamic, because it has a runtime cost to it.
One simpler solution, uses a Dictionary<string, object> in which you can safely store any IAnimalGroomer<T>.
public class AnimalGroomerClinic {
public Dictionary<string, object> animalGroomers = new Dictionary<string, object>();
public void employGroomer<T>(IAnimalGroomer<T> groomer) where T : IAnimal {
animalGroomers.Add(groomer.getAnimalType(), groomer);
}
public void Groom<T>(T animal) where T : IAnimal {
// Could also check here if the 'as' operator returned null,
// which might happen if you don't have the specific groomer
(animalGroomers[animal.getAnimalType()] as IAnimalGroomer<T>).groom(animal);
}
}
Now, this requires a cast, which you might say is unsafe. But you know it's safe due to encapsulation. If you put an IAnimalGroomer<Dog> into the hashmap under the key "dog". And request it again with the key "dog", you know it will still be an IAnimalGroomer<Dog>.
Just like with the java equivalent:
class AnimalGroomerClinic {
public Map<String, Object> animalGroomers = new HashMap<>();
public <T extends IAnimal> void employGroomer(IAnimalGroomer<T> groomer) {
animalGroomers.put(groomer.getAnimalType(), groomer);
}
#SuppressWarnings("unchecked")
public <T extends IAnimal> void Groom(T animal) {
((IAnimalGroomer<T>) animalGroomers.get(animal.getAnimalType())).groom(animal);
}
}
Which still requires an unchecked cast (even if you change Object to IAnimalGroomer<?>). The point is that you're trusting your encapsulation enough to do an unchecked cast.
It doesn't really add anything to have IAnimalGroomer<?> instead of Object in terms of type safety. Because you're encapsulation already ensures more.
It could be done for readability, to indicated what kind of objects the map holds by having IAnimalGroomer<T> implement a stub interface:
public interface IAnimalGroomerSuper {
// A stub interface
}
public interface IAnimalGroomer<T> : IAnimalGroomerSuper where T : IAnimal {...}
Then the dictionary could be:
public Dictionary<string, IAnimalGroomerSuper> animalGroomers = ...;
The point is to use a non-generic interface behind the scenes to limit the types, but only expose the generic version.
void Main()
{
var clinic = new AnimalClinic();
clinic.Add(new CatGroomer());
clinic.Add(new DogGroomer());
clinic.Add(new MeanDogGroomer());
clinic.Groom(new Cat()); //Purr
clinic.Groom(new Dog()); //Woof , Grrr!
}
public interface IAnimal {}
public interface IGroomer {}
public class Dog : IAnimal
{
public string Woof => "Woof";
public string Growl => "Grrr!";
}
public class Cat : IAnimal
{
public string Purr => "Purr";
}
public interface IGroomer<T> : IGroomer where T : IAnimal
{
void Groom(T animal);
}
public class DogGroomer : IGroomer<Dog>
{
public void Groom(Dog dog) => Console.WriteLine(dog.Woof);
}
public class MeanDogGroomer : IGroomer<Dog>
{
public void Groom(Dog dog) => Console.WriteLine(dog.Growl);
}
public class CatGroomer : IGroomer<Cat>
{
public void Groom(Cat cat) => Console.WriteLine(cat.Purr);
}
public class AnimalClinic
{
private TypedLookup<IGroomer> _groomers = new TypedLookup<IGroomer>();
public void Add<T>(IGroomer<T> groomer) where T : IAnimal
=> _groomers.Add<T>(groomer);
public void Groom<T>(T animal) where T : IAnimal
=> _groomers.OfType<T, IGroomer<T>>().ToList().ForEach(g => g.Groom(animal));
}
public class TypedLookup<T> : Dictionary<Type, IList<T>>
{
public void Add<TType>(T item)
{
IList<T> list;
if(TryGetValue(typeof(TType), out list))
list.Add(item);
else
this[typeof(TType)] = new List<T>{item};
}
public IEnumerable<TRet> OfType<TType, TRet>() => this[typeof(TType)].Cast<TRet>();
public TRet First<TType, TRet>() => this[typeof(TType)].Cast<TRet>().First();
}

InvalidCastException on Generics

Coming from the Java world, programming with generics and C# is often a headache. Like this one:
interface ISomeObject { }
class SomeObjectA : ISomeObject { }
class SomeObjectB : ISomeObject { }
interface ISomething<T> where T : ISomeObject
{
T GetObject();
}
class SomethingA : ISomething<SomeObjectA>
{
public SomeObjectA GetObject() { return new SomeObjectA(); }
}
class SomethingB : ISomething<SomeObjectB>
{
public SomeObjectB GetObject() { return new SomeObjectB(); }
}
class SomeContainer
{
private ISomething<ISomeObject> Something;
public void SetSomething<T>(ISomething<T> s) where T : ISomeObject
{
Something = (ISomething<ISomeObject>)s;
}
}
class TestContainerSomething
{
static public void Test()
{
SomeContainer Container = new SomeContainer();
Container.SetSomething<SomeObjectA>(new SomethingA());
}
}
Which results into an InvalidCastException at Something = (ISomething<ISomeObject>)s;. In Java, this would work, and I could even use (if all else fails) the generics wildcard <?>. This is not possible in C#.
While this is just an example that I put together to explain the problematic, how can this exception be eliminated? The only main constraint is that SomeContainer cannot be a generic class
** Note ** : there are many questions about this, but none of them (that I could find) address a generic class member inside a non generic class.
** Update **
Inside the method SetSomething, I added these lines :
Console.WriteLine(s.GetType().IsSubclassOf(typeof(ISomething<SomeObjectA>)));
Console.WriteLine(s.GetType().ToString() + " : " + s.GetType().BaseType.ToString());
foreach (var i in s.GetType().GetInterfaces())
{
Console.WriteLine(i.ToString());
}
which to my surprise output
False
SomeThingA : System.Object
ISomething`1[SomeObjectA]
Is this why I get this exception?
Out keyword will be a fix, if your ISomething only have methods that return T
interface ISomething<out T> where T : ISomeObject
when creating a generic interface, you can specify whether there is an implicit conversion between interface instances that have different type arguments.
It is called Covariance and Contravariance
Eric Lippert have a good series of articles why we need to think about this, here interface variance is used
Here is my code, which works as expected for me
interface ISomeObject { }
class SomeObjectA : ISomeObject { }
class SomeObjectB : ISomeObject { }
interface ISomething<out T> where T : ISomeObject
{
T GetObject();
}
class SomethingA : ISomething<SomeObjectA>
{
public SomeObjectA GetObject() { return new SomeObjectA(); }
}
class SomethingB : ISomething<SomeObjectB>
{
public SomeObjectB GetObject() { return new SomeObjectB(); }
}
class SomeContainer
{
private ISomething<ISomeObject> Something;
public void SetSomething<T>(ISomething<T> s) where T : ISomeObject
{
Something = (ISomething<ISomeObject>)s;
}
}
class TestContainerSomething
{
static public void Test()
{
SomeContainer Container = new SomeContainer();
Container.SetSomething<SomeObjectA>(new SomethingA());
}
}
Sometimes it is useful to let a generic interface implement a non generic one to circumvent the missing <?>
interface ISomething
{
object GetObject();
}
interface ISomething<T> : ISomething
where T : ISomeObject
{
T GetObject();
}
public class SomeImplementation<T> : ISomething<T>
{
public T GetObject()
{
...
}
object ISomething.GetObject()
{
return this.GetObject(); // Calls non generic version
}
}
A collection can then be typed with the non generic interface
var list = new List<ISomething>();
list.Add(new SomeImplementation<string>());
list.Add(new SomeImplementation<int>());

One function implementing Generic and non-generic interface

Lets say I have a class, which implements a generic interface
public interface IItem {}
public interface IStuff<out TItem> where TItem : IItem
{
TItem FavoriteItem { get; }
}
public class MyStuff<TItem> : IStuff<TItem> where TItem : IItem
{
public TItem FavoriteItem
{
get { throw new NotImplementedException(); }
}
}
I have also one non-generic interface
public interface IFavoriteItem
{
IItem FavoriteItem { get; }
}
I'd like to make MyStuff class implement this IFavoriteItem interface. Since TItem implements IItem it seems for me, that public TItem FavoriteItem property is implementing IFavoriteItem already.
But compiler doesn't think so, and it wants me to declare a separate IItem IFavoriteItem.FavoriteItem in MyClass. Why is it so? Isn't c# covariance the thing that should play here and solve my problem?
Thanks
The reason for this is that FavoriteItem of IFavoriteItem may not be IItem, where on the IFavoriteItem, it must be an IItem. The only way to solve this is by:
IItem IFavoriteItem.FavoriteItem
{
get { return FavoriteItem; }
}
This will simply shortcut the call to your TItem implementation.
A good example of where this is used quite often is with the implementation of IEnumerable<>. These often look like this:
public class MyEnumerable : IEnumerable<T>
{
public IEnumerator<T> GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}

Categories