I'm trying some simple code to understand the generics in C#. The purpose of the code here is to have a trainer that has her own animal and will ask it to do various stuff (for the sake of the example, to jump).
The problem is with the constructor of the trainer. I would like to be able to pass a Dog, or a Cat. They both inherit from the same class, but because I specified the type definition it seems I can't pass them as argument, they can't be both valid. Is there a way to specify a generic class like "Animal" so I could pass a dog or a cat and keep it as a member?
class AnimalDefinition
{
public Fur Fur;
}
class DogDefinition : AnimalDefinition
{
public BarkSound Bark;
}
class CatDefinition : AnimalDefinition
{
public MeowSound Meow;
}
class Animal<TDefinition> where TDefinition : AnimalDefinition
{
public TDefinition Definition;
public void Jump()
{
Console.WriteLine("Jump.");
}
}
class Dog : Animal<DogDefinition>
{
public Dog(DogDefinition def)
{
Definition = def;
}
}
class Cat : Animal<CatDefinition>
{
public Cat(CatDefinition def)
{
Definition = def;
}
}
class Trainer
{
Animal _animal;
public Trainer(Animal myAnimal)
{
_animal = myAnimal;
}
public MakeJump()
{
_animal.Jump();
}
public Listen()
{
// if T is DogDefinition hear barking
// else if T is CatDefinition hear a meowing, etc
}
}
EDIT: Additional question following Chris Berger's answer (which works, but I didn't change the code to keep the question/answer logical). I added a definition member in the Animal class. Is there any way I can access Bark or Meow from inside the Trainer class or will I have to derivate the class Trainer with CatTrainer : Trainer<CatDefinition>? That is, is there something similar to what we have with classes,
if(T is CatDefinition)
{ // Meowing}
else
{}
I think I agree with the first commenter, that you don't necessarily want generics for this, but assuming you have some other reason for wanting generics...
The solution here is to create a class Animal, which Animal<T> derives from.
For example:
public class Animal
{
public virtual void Jump()
{
Console.WriteLine("Jump.");
}
}
public class Animal<T> : Animal where T : AnimalDefinition
{
public override void Jump()
{
//you can override Jump here if you want to
}
}
public class Dog : Animal<DogDefinition> {}
public class Cat : Animal<CatDefinition> {}
Or, actually, a second option is to give Trainer visibility to the generic parameter:
public class Animal<T> where T : AnimalDefinition
{
public void Jump()
{
Console.WriteLine("Jump.");
}
}
public class Dog : Animal<DogDefinition> {}
public class Cat : Animal<CatDefinition> {}
public class Trainer<T> where T : AnimalDefinition
{
Animal<T> _animal;
public Trainer(Animal<T> myAnimal)
{
_animal = myAnimal;
}
public MakeJump()
{
_animal.Jump();
}
}
And as a tangent... this might be a good place to use a self-referential generic.
public class Animal<T> where T : Animal<T> { }
public class Dog : Animal<Dog> { }
Here's a little more reading on that pattern: https://blogs.msdn.microsoft.com/simonince/2008/06/12/generics-the-self-referencing-generics-pattern/
Related
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){}
Is there any way to use an abstract class as a generic type? I've given a very simple example below to simulate what I need. I get an error that an implicit conversion cannot be made for variable genericBehavior.
public abstract class AnimalBase { } // Cannot edit
public class Dog : AnimalBase { } // Cannot edit
public class Cat : AnimalBase { } // Cannot edit
public interface IAnimalBehavior<T> where T : AnimalBase { }
public class CatBehavior : IAnimalBehavior<Cat> { }
public class DogBehavior : IAnimalBehavior<Dog> { }
public class Startup
{
public Startup()
{
IAnimalBehavior<Cat> catBehavior = new CatBehavior();
IAnimalBehavior<AnimalBase> genericBehavior = new CatBehavior(); // This doesn't work
}
}
Ultimately, in my .NET Core Startup, I'd like to be able to have the following:
services.AddScoped<IAnimalBehavior<AnimalBase>, CatBehavior>();
or
services.AddScoped<IAnimalBehavior, CatBehavior>();
What's the best approach?
Since are using IAnimalBehavior<AnimalBase>, and not IAnimalBehavior<Cat>, then this structure works:
public interface IAnimalBehavior{ }
public class CatBehavior : IAnimalBehavior { }
public class DogBehavior : IAnimalBehavior { }
...
services.AddScoped<IAnimalBehavior, CatBehavior>();
Having IAnimalBehavior<T> makes sense if you differentiate on T:
public class CatBehavior : IAnimalBehavior<Cat> { }
public class DogBehavior : IAnimalBehavior<Dog> { }
...
services.AddScoped<IAnimalBehavior<Cat>, CatBehavior>();
services.AddScoped<IAnimalBehavior<Dog>, CatBehavior>();
I wanted to make the following inheritance with included generics, but the final cast
a as A<XBase> always results in null, because the cast is not valid. Could anybody elaborate on why this cast would be invalid, as well as maybe a solution to this problem.
public class XBase {}
public interface A<T> where T : XBase
{
//Edited
void Method(T param);
}
public class Implementor : A<Implementor.ImplementorX >
{
public class ImplementorX : XBase {public int a;}
//Edited
void Method(ImplementorX param) {}
}
public class HelloWorld
{
public static void Main(string[] args)
{
var a = new Implementor();
var castRes = a as A<XBase>;
Console.WriteLine(castRes != null);
}
}
see live example https://rextester.com/BTNVT61833
EDITED: Added a method to interface A<T> bc else it could be solved with #DavidG's response
If you make an explicit cast:
var castRes = A<XBase>(a);
then you will see the following error:
Unable to cast object of type '' to type '`
Why? In my view, it is better to understand using real world example. I've renamed classes based on this explanation. There are comments which maps explanations to your classes in question.
Abstractions:
// XBase
public class Animal { }
// class ImplementorX : XBase {public int a;}
public class Bird : Animal
{
public string WingColor { get; set; }
}
// interface A<T> where T : XBase
public interface IHat<T> where T : Animal
{
void Hide(T param);
T Pull();
}
Concrete implementations:
// class Implementor : A<Implementor.ImplementorX >
public class Peacock : IHat<Bird>
{
// void Method(ImplementorX param) {}
void IHat<Bird>.Hide(Bird param)
{ }
public Bird Pull()
{ }
}
and how it can be called:
public static void Main(string[] args)
{
Peacock peacockHat = new Peacock();
IHat<Animal> animalHat = (IHat<Animal>) peacockHat; // runtime error 'Unable to cast
// object of type 'HelloWorld.Peacock' to type 'HelloWorld.IHat`1
// because
animalHat.Hide(new Dolphin()); // Hide a dolphin in a peacock hat?
}
So we cannot hide hat of Peacock from Dolphin. It is not okay. CLR prevents us from making inappropriate actions.
In short:
In short, imagine you have two animals such as Wolf and Sheep. And these classes implements IAnimal interface:
public interface IAnimal
{ }
public class Wolf: IAnimal
{ }
public class Sheep : IAnimal
{ }
So Sheep, Wolf classes implement the inherited interface IAnimal:
IAnimal
/ \
/ \
Sheep Wolf
And then these animals can be put in cage:
public class Cage<T> where T : IAnimal
{
public void Put(T animal)
{ }
}
Then you create a cage for Sheep. After that somebody wants to cast Sheep cage to IAnimal:
Cage<Sheep> sheepCage = new Cage<Sheep>();
sheepCage.Put(new Sheep());
Cage<IAnimal> animalCage = (Cage<Wolf>)sheepCage; // compile error
// if there were no error, then you will be able to do:
animalCage.Put(new Wolf()); // it is not good idea
I have a Partial View that I want be able to use with several different models. Is there any way to find out what the Child class of an object is when it is being passed in as its parent?
For example:
Model:
public class Animal { }
public class Dog : Animal { }
public class Cat : Animal { }
Controller:
public class AnimalActionController : Controller
{
public ActionResult MakeAnimalSound(Animal animal)
{
if (animal is Dog)
{
return PartialView("~/Views/_AnimalActionView.cshtml", new{sound="Woof"});
}
if (animal is Cat)
{
return PartialView("~/Views/_AnimalActionView.cshtml", new{sound="Meow"});
}
}
}
Parent View of Dog page:
#model Test.Models.Dog
#Html.Action("MakeAnimalSound", "AnimalAction", new { Model })
Right now if I were to do something like this example the if statements in the Controller only see animal as Animal and not as Dog or Cat which it originally was.
Anyone know how to do this? I feel like it should be simple.
A better choice for this would be to do something like this. Testing class types is a poor design and considered a code smell in most cases (sometimes it's necessary, but there's usually other ways to accomplish what you want without it):
public class Animal
{
public virtual Sound {get;}
}
public class Dog : Animal
{
public override Sound {get {return "Woof";}}
}
public class Cat : Animal
{
public override Sound {get {return "Meow";}}
}
public ActionResult MakeAnimalSound(Animal animal)
{
return PartialView("~/Views/_AnimalActionView.cshtml", new{sound=animal.Sound});
}
If you call the object's GetType() method, you will get an object that will tell you everything you need to know. See the MSDN page on System.Type.
The following program outputs Child.
internal class Parent {
private string Something { get; set; }
}
internal class Child : Parent {
private int SomethingElse { get; set; }
}
internal class Program {
private static void Main(string[] args) {
Parent reallyChild = new Child();
Console.WriteLine(reallyChild.GetType().Name);
Console.ReadLine();
}
}
I have an abstract class "MainClass" which composes "Animal" class. I derive two classes TypeA and TypeB from abstract class which contains common functionality. TypeA and TypeB classes need to be extended to include their own specific functionality.
For example, TypeA would require to add cat functionality under Animal class. So that test application will be accessing the cat class like this typeA._animals._cat?
I know types cannot be added at runtime but is there any other design pattern that could solve my problem?
public abstract class MainClass
{
public Animal _animals;
}
public class Animal
{
public Tiger _tiger;
}
public class Tiger
{
public int type { get { return "Tiger" ; } }
}
public class Cat
{
public int type { get { return "Car" ; } }
}
public class Leopard
{
public int type { get { return "Leopard" ; } }
}
public class TypeA : MainSession
{
//Would like to add type Cat to Animal class
}
public class TypeB : MainSession
{
//Would like to add type Leopard to Animal class
}
Firstly, I believe that Tiger, Cat, Leopard should be inheriting from Animal. Now, you may use a generic base class with type constraints to do the same. For example,
public abstract class MainClass<A> where A:Animal
{
public A _animals;
}
public abstract class Animal
{
...
}
public class Tiger : Animal
{
...
}
public class Cat : Animal
{
...
}
public class Leopard : Animal
{
...
}
public class TypeA : MainSession<Cat>
{
...
}
public class TypeB : MainSession<Leopard>
{
....
}
The first thing you should do is to create an inheritance:
public interface IAnimal
{
string SpeciesName {get; }
}
And implement it:
public class Tiger : IAnimal
{
public string SpeciesName { get { return "Tiger" ; } }
}
public class Cat : IAnimal
{
public string SpeciesName { get { return "Cat" ; } }
}
Let's use it:
public abstract class MainSession
{
private List<IAnimal> _animals;
public IEnumerable<IAnimal> Animals {get { return _animals; }}
proteced void AddAnimal(IAnimal animal)
{
_animals.Add(animal);
}
}
public class TypeA : MainSession
{
public TypeA()
{
AddAnimal(new Tiger());
}
}
public class TypeB : MainSession
{
public TypeB()
{
AddAnimal(new Leopard());
}
}
You could also convert the AddAnimal into a factory method:
public abstract class MainSession
{
private List<IAnimal> _animals;
public IEnumerable<IAnimal> Animals {get { return _animals; }}
protected IAnimal CreateAnimal(string speciesName)
{
// Either use reflection to find the correct species,
// or a simple switch like below:
switch (speciesName)
{
case "tiger":
return new Tiger();
break;
}
}
}
Having the factory in MainSession breaks Single Responsibility Principle, so I would break it out into a separate class.
Yes, Using Abstract Factory Pattern can solve your problem. Check this out on :
http://en.wikipedia.org/wiki/Abstract_factory_pattern
Your main class needs to have a List<Animal> _animals instead of Animal _animals. The Tiger, Cat, and Leopard classes should inherit from the Animal class. You can then put the type property in the Animal base class. At runtime you can add as many Animals to the _animals list as you would like, and since the type property is in the Animal base class you will have access to it in all derived classes.