I was feeling quite clever as I worked out how to create subclasses in C# for an ASP.NET project, then I found a problem - I didn't know how to create an object of the right subclass based on the results of a SQL query.
Say you have a class called Animal and two subclasses called Zebra and Elephant. You get the idea?
What I want to do is perform a SQL query and if the row returned has row["Type"]="Zebra" then load a Zebra object (or if it's an Elephant then..).
So, in principle, the Animal class would have a static method:
class Animal{
public static Animal Load(DataRow row){
if (row["Type"]=="Zebra"){
return new Zebra();
}
}
class Zebra : Animal{
//some code here
}
Is this at all possible or have I just plain got the idea of subclasses wrong. It should be obvious I'm no OO expert.
Thanks in advance,
Jake
You can implement the method factory pattern.
http://en.wikipedia.org/wiki/Factory_method_pattern
Try this:
public interface IAnimal
{ }
public class Animal : IAnimal
{
public static IAnimal Load(String type)
{
IAnimal animal = null;
switch (type)
{
case "Zebra" :
animal = new Zebra();
break;
case "Elephant" :
animal = new Elephant();
break;
default:
throw new Exception();
}
return animal;
}
}
public class Zebra : Animal
{
public int NrOfStripes { get; set; }
public static Zebra ZebraFactory()
{
return new Zebra();
}
}
public class Elephant : Animal
{
public int LengthOfTrunk { get; set; }
}
And to try it:
class Program
{
static void Main(string[] args)
{
IAnimal zebra = Animal.Load("Zebra");
IAnimal elephant = Animal.Load("Elephant");
}
}
I think it's fine:
public class Animal
{
public static Animal Load(string row)
{
if (row == "Zebra")
{
return new Zebra();
}
else if (row == "Elephant")
{
return new Elephant();
}
return null;
}
}
public class Zebra : Animal
{
public new string ToString()
{
return "Zebra";
}
}
public class Elephant : Animal
{
public new string ToString()
{
return "Elephant";
}
}
static void Main(string[] args)
{
Animal a1 = Animal.Load("Zebra");
System.Console.WriteLine(((Zebra)a1).ToString());
System.Console.WriteLine(((Elephant)a1).ToString()); // Exception
Animal a2 = Animal.Load("Elephant");
System.Console.WriteLine(a2.ToString());
}
Related
In C# I know there is a way of switching method calls based on the concrete type of an abstract parameter at run time.
So in the example below the entire Wash(Animal) method is not needed and C# will know which Cat/Dog method to call based on the concrete type of Animal at run time. There's syntax to do this, I've done this before but I can't for the life of me remember what it is.
public void Wash(Animal animal)
{
switch (animal)
{
case Cat cat:
Wash(cat);
break;
case Dog dog:
Wash(dog);
break;
}
}
public void Wash(Cat cat)
{
}
public void Wash(Dog dog)
{
}
Could be done using double dispatch...
abstract class Animal
{
public abstract void TakeBath(AnimalWasher washer);
}
class Cat : Animal
{
public override void TakeBath(AnimalWasher washer)
{
washer.Wash(this);
}
}
class Dog : Animal
{
public override void TakeBath(AnimalWasher washer)
{
washer.Wash(this);
}
}
class AnimalWasher
{
public void Wash(Cat cat)
{
Console.WriteLine("washing a cat");
}
public void Wash(Dog dog)
{
Console.WriteLine("washing a dog");
}
}
class Program
{
static async Task Main(string[] args)
{
AnimalWasher washer = new AnimalWasher();
Animal dog = new Dog();
Animal cat = new Cat();
dog.TakeBath(washer);
cat.TakeBath(washer);
}
Thank you Mr Skeet for scratching my itch. Dynamic binding is exactly what I was trying to remember.
public void PetGroom(Animal animal)
{
Wash(animal as dynamic);
}
public void Wash(Cat cat)
{
}
public void Wash(Dog dog)
{
}
Code to demonstrate the problem:
static void Main(string[] args)
{
var a = new A();
var b = new B();
Base<>[] all = new Base<>[] { a, b }; // doesn't work
}
class Base<T>
{
public string Caption { get { return typeof(T).ToString(); } }
}
class A : Base<A> { }
class B : Base<B> { }
Perhaps I went the wrong direction. Idea was to move Caption into base class (Base become generic). Non-generic version works without problems:
var all = new Base[] { a, b }; // no problems for as long as Base is not generic
There's no Type<?> in C# - you always have to specify a concrete generic type.
The only way around this is to make Base<T> inherit a non-generic base-class, or implement a non-generic interface. You could then use that as the type of the array.
EDIT:
In your case this is extremely simple, since the part of the interface you want doesn't include the generic type argument. So you can simply do either:
public abstract class Superbase
{
public abstract string Caption { get; }
}
public class Base<T>: Superbase
{
public override string Caption { get { return typeof(T).Name; } }
}
Or, using an interface:
public interface IBase
{
string Caption { get; }
}
public class Base<T>: IBase
{
public string Caption { get { return typeof(T).Name; } }
}
Your array would then be Superbase[] or IBase[], respectivelly. In both cases, you can see that I'm not actually providing an implementation - both the declarations are "abstract", in a sense.
In general, I'm trying to keep the non-generic stuff in a non-generic base class, rather than stuffing it in the derived generic classes. It just feels more clean :)
based on #Luaan ideea, here is an implementation:
class Program
{
static void Main(string[] args)
{
var a = new A();
var b = new B();
var arr = new Base[] { a, b};
foreach (var obj in arr)
Console.WriteLine(obj.Caption);
Console.ReadKey();
}
}
public class Base<T> : Base
{
public override string Caption
{
get { return typeof (T).ToString(); }
}
}
public class A : Base<A> { }
public class B : Base<B> { }
public abstract class Base
{
public abstract string Caption { get; }
}
Instead of trying to use inheritance (which will lead to more problems down the line), use an extension method instead:
public interface IClassAORClassB {}
class A : IClassAORClassB { }
class B : IClassAORClassB { }
public static class Captions
{
public static string Caption<T>(this T obj) where T : IClassAORClassB
{
return obj.GetType().ToString();
}
}
static void Main(string[] args)
{
var a = new A();
var b = new B();
var all = new IClassAORClassB[] { a, b }; // works just fine
Console.WriteLine(all[0].Caption()); // prints A
Console.WriteLine(all[1].Caption()); // prints B
}
I have a problem, which I can't explain in simple words, so I will use an examlpe to ilustrate what I have on mind.
I have three classes Cow, Horse, Sheep. And class Animals. And now I want the clas Animal to store list of animals but only one specified species(the user select type in constructor). Now i don't want to use templates and I don't want to create three different list in one class. So I wonder if there is other way to do that. I think it can be done like this:
public class Animal
{
}
public class Cow : Animal
{
}
public class Horse : Animal
{
}
public class Sheep : Animal
{
}
public class Animals
{
public String Type { get; protected set; }
public List<Animal> List { get; set;}
public Animals(String type)
{
this.Type = type;
switch (type)
{
case "Cow":
List = new List<Cow>();
break;
case "Horse":
List = new List<Horse>();
break;
case "Sheep":
List = new List<Sheep>();
break;
}
}
}
Of course that code is only sample and it doesn't work, but I think it ilustrate the problem I have. I'm sure that I saw something similar in the past but I dont know if it was C# or Java. And if I remeber it looked something like that:
Animal animal = new Cow();
Tell me if there is any way to do that.
What about
public class Animals<T>
where T : Animal
{
public List<T> List {get;set;}
}
var Cows = new Animals<Cow>();
You can create the list as List<Animal> in each case, and it will happily store any object derived from Animal. The problem is with enforcement of the objects in the list being the same type -- it's not clear where you want to enforce that but I took a stab at it below, by keeping the desired Type in a member variable.
If all you want is an enumerator of a particular type, you can use OfType (thanks Kevin D) to generate the enumerator. I know you said you don't want to use generics, but your Animals class does not have to have a type parameter, and using template methods is a more elegant solution (IMHO).
public class Animal
{
}
public class Cow : Animal
{
}
public class Animals
{
private Type _animalType;
private List<Animal> _animals = new List<Animal>();
public Animals(Type animalType)
{
_animalType = animalType;
}
public IEnumerable<T> GetAnimals<T>() where T : Animal
{
return _animals.OfType<T>();
}
public void Add(Animal animal)
{
if (! _animalType.IsAssignableFrom(animal.GetType()))
throw new Exception("Expected a " + _animalType.Name + " but was passed a " + animal.GetType().Name);
_animals.Add(animal);
}
}
public class Program
{
public static void Main()
{
Animals animals = new Animals(typeof(Cow));
animals.Add(new Cow());
IEnumerable<Cow> cows = animals.GetAnimals<Cow>();
foreach (var cow in cows)
{
// do something
}
}
}
I believe that Generics is the best way to solve your problem, by the way I hope this code help you.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication7
{
public class Animal
{
}
public class Cow : Animal
{
}
public class Horse : Animal
{
}
public class Sheep : Animal
{
}
public class Animals
{
protected ArrayList List { get; set; }
protected Type Type { get; set; }
public Animals(Type type)
{
this.Type = type;
this.List = new ArrayList();
}
public void AddAnimal(Animal animal)
{
if (animal.GetType() == this.Type)
this.List.Add(animal);
else
throw new Exception("Not expected type");
}
}
class Program
{
static void Main(string[] args)
{
var s1 = new Sheep();
var s2 = new Sheep();
var c1 = new Cow();
var sheepList = new Animals(typeof(Sheep));
sheepList.AddAnimal(s1);
sheepList.AddAnimal(s2);
sheepList.AddAnimal(c1);//throws an exception
}
}
}
I came across this recently while writing the code. Is there a way we can write a code in base class so it identifies the correct extension method based on the type?
namespace GenericsInheritance
{
public class Animal { }
public class Dinasaur : Animal { }
public class Dragon : Animal { }
public abstract class Zoo<T> where T : Animal
{
public virtual string IdentifyYourSelf(T record)
{
//Calling extension method
string name = record.IdentifyYourSelf();
return name;
}
}
public class DinasaurZoo : Zoo<Dinasaur>
{
//I could use this, just wanted to try if base class method does identify the correct extension method for the type.
//public override string IdentifyYourSelf(Dinasaur record)
//{
// return record.IdentifyYourSelf();
//}
}
public class DragonZoo : Zoo<Dragon> { }
public class AnimalZoo : Zoo<Animal> { }
//Extensions methods class.
public static class LieDetector
{
public static string IdentifyYourSelf(this Animal record) { return "Animal"; }
public static string IdentifyYourSelf(this Dinasaur record) { return "Dinasaur"; }
public static string IdentifyYourSelf(this Dragon dog) { return "Dragon"; }
//It works if I use this.
//public static string IdentifyYourSelf<T>(this T record) where T : Animal
//{
// if (record is Dinasaur) { var dinasaur = record as Dinasaur; return IdentifyYourSelf(dinasaur); }
// else if (record is Dragon) { var dragon = record as Dragon; return IdentifyYourSelf(dragon); }
// else return "I do not exist";
//}
}
public class FbiInterrogation
{
public static void Main(string[] args)
{
var animal = new Animal();
var dinasaur = new Dinasaur();
var dragon = new Dragon();
var dinasaurZoo = new DinasaurZoo();
var dragonZoo = new DragonZoo();
var animalZoo = new AnimalZoo();
string name = dinasaurZoo.IdentifyYourSelf(dinasaur); //Prints Animal expecting Dinasaur
name = dragonZoo.IdentifyYourSelf(dragon); //Prints Animal expecting Dragon
name = animalZoo.IdentifyYourSelf(animal); //Prints Animal
Console.ReadKey();
}
}
}
Extension methods are resolved according to the static type of the variable on which they're called, not the run-time type. So the answer to your question is "no" -- you have to do it via an override in the derived class, or by cumbersome type checking, as you indicate in your question.
This could actually be achieved using reflection, though I'm not sure if it's the best idea to do so:
public abstract class Zoo<T> where T : Animal
{
public virtual string IdentifyYourSelf(T record)
{
return typeof(LieDetector).GetMethod("IdentifyYourSelf", new[] {typeof(T)}, null).Invoke(record, new object[] {record}) as string;
}
}
I have a method which uses a generic parameter and requires the downcasted form of the instance. For example,
public abstract class Animal {
}
public class Dog : Animal {
}
public class Cat : Animal {
}
public class AnimalHandler {
public virtual void Pet<T>(T animal)
{
}
}
Given a collection of animals.
public List<Animal> Animals { get; set; }
How do I downcast individual animals before calling the Pet method?
I currently having working in this form.
if (animal is Dog) {
_animalHandler.Pet((Dog)animal);
}
if (animal is Cat) {
_animalHandler.Pet((Cat)animal);
}
Ideally, it would be something of this form.
var type = animal.GetType();
_animalHandler.Pet(animal.CastTo(type));
Clarification: I need the instance to be of the downcasted type before it is passed to the method. I need a Dog or Cat specifically to be passed in.
You can accomplish this using the new .NET 4 dynamic keyword:
namespace Rextester
{
public class Program
{
public abstract class Animal {
}
public class Dog : Animal {
}
public class Cat : Animal {
}
public class AnimalHandler {
public virtual void Pet<T>(T animal) {
Console.WriteLine(typeof(T));
}
}
public class Problem {
public List<Animal> Animals { get; set; }
private readonly AnimalHandler _animalHandler;
public Problem(AnimalHandler animalHandler) {
_animalHandler = animalHandler;
Animals = new List<Animal> { new Cat(), new Dog() };
}
public void MakeDecision() {
foreach (var animal in Animals) {
_animalHandler.Pet(animal);
}
}
}
public static void Main(string[] args)
{
List<Animal> animals = new List<Animal>();
animals.Add(new Dog());
animals.Add(new Cat());
var handler = new AnimalHandler();
handler.Pet((dynamic)animals[0]);
handler.Pet((dynamic)animals[1]);
}
}
}
Notice the cast to dynamic in the calls to Pet. Though doing it this way negates the necessity of Pet being generic in the first place.
If, as your clarification says, you "Need a concrete Dog or Cat to be passed in" then your method cannot take a generic Animal.
However, what I suspect you're missing is that the Handler should not need to know what type of animal it has, only how to Handle that Animal. See this expanded example:
public abstract class Animal {
public abstract void Speak();
}
public class Dog : Animal {
public override void Speak(){ Console.WriteLine("WOOF!! You're great."); }
}
public class Cat : Animal {
public override void Speak(){ Console.WriteLine("Meow. Im better than you."); }
}
public class AnimalHandler {
public virtual void Pet<T>(T animal) where T : Animal
{
animal.Speak();
}
}
When executing this with the following code:
List<Animal> animals = new List<Animal>();
animals.Add(new Dog());
animals.Add(new Cat());
var handler = new AnimalHandler();
handler.Pet(animals[0]);
handler.Pet(animals[1]);
Im sure you can imagine the output (If not, Live example: http://rextester.com/UJZRB90548). You see from this, I only have a list of Base Animal, but when it is passed in to the Handler, the correct method is called.
You have a few alternatives. One approach would be to have sub-classes of AnimalHandler per animal type and manually dispatch to the correct one:
public class AnimalHandler
{
public void Pet(Animal animal)
{
if (animal is Cat)
{
this.catHandler.Pet((Cat) animal);
}
else if (animal is Dog)
{
this.dogHandler.Pet((Dog) animal);
}
else
{
throw new ArgumentOutOfRangeException("animal");
}
}
private readonly CatHandler catHandler;
private readonly DogHandler dogHandgler;
}
As an alternative to all the 'if's and 'is's you could add an AnimalType enum property to the Animal class and use a switch statement.
The above approach could be made a bit more generic and extensible by creating an interface to represent a specific animal type handler:
public enum AnimalType
{
Cat,
Dog,
}
public interface ISpecificAnimalHandler
{
AnimalType AnimalType { get; }
void Pet(Animal animal);
}
public class AnimalHandler
{
public AnimalHandler()
{
var handlers = new ISpecificAnimalHandler[] { new CatHandler(), new DogHandler() };
this.handlersByAnimal = handlers.ToDictionary(handler => handler.AnimalType, handler);
// ...
}
public void Pet(Animal animal)
{
ISpecificAnimalHandler handler;
if (!this.handlersByAnimalType.TryGet(animal.AnimalType, out handler))
{
throw new ArgumentOutOfRangeException("Animal of type " + animal.GetType().Name " not supported.");
}
handler.Pet(animal);
}
private IDictionary<AnimalType, ISpecificAnimalHandler> handlerByAnimalType;
}
public class CatHandler : ISpecificAnimalHandler
{
public AnimalType AnimalType
{
get { return AnimalType.Cat;
}
public void Pet(Animal animal)
{
var cat = (Cat) animal;
// do petting, meow
}
}
Another, different, option is to use dynamic dispatch:
public class AnimalHandler
{
public void Pet(Animal animal)
{
PetAnimal((dynamic) animal); // will dispatch to most appropriate method at runtime
}
public void PetAnimal(Cat cat)
{
// do petting, meow
}
public void PetAnimal(Dog dog)
{
// do petting, woof
}
}