Is there a better way of binding a list of base class to a UI other than downcasting e.g:
static void Main(string[] args) {
List<Animal> list = new List<Animal>();
Pig p = new Pig(5);
Dog d = new Dog("/images/dog1.jpg");
list.Add(p);
list.Add(d);
foreach (Animal a in list)
{
DoPigStuff(a as Pig);
DoDogStuff(a as Dog);
}
}
static void DoPigStuff(Pig p)
{
if (p != null)
{
label1.Text = String.Format("The pigs tail is {0}", p.TailLength);
}
}
static void DoDogStuff(Dog d) {
if (d != null)
{
Image1.src = d.Image;
}
}
class Animal {
public String Name { get; set; }
}
class Pig : Animal{
public int TailLength { get; set; }
public Pig(int tailLength)
{
Name = "Mr Pig";
TailLength = tailLength;
}
}
class Dog : Animal {
public String Image { get; set; }
public Dog(String image)
{
Name = "Mr Dog";
Image = image;
}
}
Why not make Animal include an abstract method that Pig and Dog are forced to implement
public class Animal
{
public abstract void DoStuff();
}
public Dog : Animal
{
public override void DoStuff()
{
// Do dog specific stuff here
}
}
public Pig : Animal
{
public override void DoStuff()
{
// Do pig specific stuff here
}
}
This way each specific class takes responsibility for its actions, making your code simpler. You also won't need to cast inside your foreach loop.
When faced with this type of problem, I follow the visitor pattern.
interface IVisitor
{
void DoPigStuff(Piggy p);
void DoDogStuff(Doggy d);
}
class GuiVisitor : IVisitor
{
void DoPigStuff(Piggy p)
{
label1.Text = String.Format("The pigs tail is {0}", p.TailLength);
}
void DoDogStuff(Doggy d)
{
Image1.src = d.Image;
}
}
abstract class Animal
{
public String Name { get; set; }
public abstract void Visit(IVisitor visitor);
}
class Piggy : Animal
{
public int TailLength { get; set; }
public Piggy(int tailLength)
{
Name = "Mr Pig";
TailLength = tailLength;
}
public void Visit(IVisitor visitor)
{
visitor.DoPigStuff(this);
}
}
class Doggy : Animal
{
public String Image { get; set; }
public Doggy(String image)
{
Name = "Mr Dog";
Image = image;
}
public void Visit(IVisitor visitor)
{
visitor.DoDogStuff(this);
}
}
public class AnimalProgram
{
static void Main(string[] args) {
List<Animal> list = new List<Animal>();
Pig p = new Pig(5);
Dog d = new Dog("/images/dog1.jpg");
list.Add(p);
list.Add(d);
IVisitor visitor = new GuiVisitor();
foreach (Animal a in list)
{
a.Visit(visitor);
}
}
}
Thus the visitor pattern simulates double dispatch in a conventional single-dispatch object-oriented language such as Java, Smalltalk, C#, and C++.
The only advantage of this code over jop's is that the IVisitor interface can be implemented on a different class later when you need to add a new type of visitor (like a XmlSerializeVisitor or a FeedAnimalVisitor).
Another way to do this is to perform a typecheck before calling the method:
if (animal is Pig) DoPigStuff();
if (animal is Dog) DoDogStuff();
What you are looking for is multiple-dispatch. NO - C# doesn't support multiple-dispatch. It only supports single-dispatch. C# can only dynamically invoke a method based on the type of the receiver (i.e. the object at the left hand side of the . in the method call)
This code uses double-dispatch. I'll let the code speak for itself:
class DoubleDispatchSample
{
static void Main(string[]args)
{
List<Animal> list = new List<Animal>();
Pig p = new Pig(5);
Dog d = new Dog(#"/images/dog1.jpg");
list.Add(p);
list.Add(d);
Binder binder = new Binder(); // the class that knows how databinding works
foreach (Animal a in list)
{
a.BindoTo(binder); // initiate the binding
}
}
}
class Binder
{
public void DoPigStuff(Pig p)
{
label1.Text = String.Format("The pigs tail is {0}", p.TailLength);
}
public void DoDogStuff(Dog d)
{
Image1.src = d.Image;
}
}
internal abstract class Animal
{
public String Name
{
get;
set;
}
protected abstract void BindTo(Binder binder);
}
internal class Pig : Animal
{
public int TailLength
{
get;
set;
}
public Pig(int tailLength)
{
Name = "Mr Pig";
TailLength = tailLength;
}
protected override void BindTo(Binder binder)
{
// Pig knows that it's a pig - so call the appropriate method.
binder.DoPigStuff(this);
}
}
internal class Dog : Animal
{
public String Image
{
get;
set;
}
public Dog(String image)
{
Name = "Mr Dog";
Image = image;
}
protected override void BindTo(Binder binder)
{
// Pig knows that it's a pig - so call the appropriate method.
binder.DoDogStuff(this);
}
}
NOTE: Your sample code is much more simpler than this. I think of double-dispatch as one of the heavy artilleries in C# programming - I only take it out as a last resort. But if there are a lot of types of objects and a lot different types of bindings that you need to do (e.g. you need to bind it to an HTML page but you also need to bind it to a WinForms or a report or a CSV), I would eventually refactor my code to use double-dispatch.
You're not taking full advantage of your base class. If you had a virtual function in your Animal class that Dog & Pig override, you wouldn't need to cast anything.
Unless you have a more specific example, just override ToString().
I think you want a view-class associated with a factory.
Dictionary<Func<Animal, bool>, Func<Animal, AnimalView>> factories;
factories.Add(item => item is Dog, item => new DogView(item as Dog));
factories.Add(item => item is Pig, item => new PigView(item as Pig));
Then your DogView and PigView will inherit AnimalView that looks something like:
class AnimalView {
abstract void DoStuff();
}
You will end up doing something like:
foreach (animal in list)
foreach (entry in factories)
if (entry.Key(animal)) entry.Value(animal).DoStuff();
I guess you could also say that this is a implementation of the strategy pattern.
Related
I have a parent class called Snack with subclasses Drink and Sweets. I want to store my Snacks in a "VendingMachine" Class where there is a list for each of the Products. However, I don't want to write the same method for each type of Snack. How would you write this as a generic method ?
// DRINKS LIST
List<Drink> drinks = new List<Drink>();
public List<Drink> Drinks { get => drinks; set => drinks = value; }
private void FillWithProducts <Product> (params Product[] products) where Product : Snack
{
Type typeParameter = typeof(Product);
Type drink = typeof(Drink);
foreach (Product p in products)
{
if (typeParameter.Equals(drink))
{
Drinks.Add(p);
}
}
}
If you really need to store each kinds of products in theair own list, you can use a dynamically populated dictionary where the key is the type, something like this.
private readonly Dictionary<Type, List<Product>> storeByType = new();
public List<Drink> Drinks => (List<Drink>)this.storeByType[typeof(Drink)]
private void FillWithProducts<Product>(params Product[] products) where Product : Snack
{
foreach (Product p in products)
{
var key = p.GetType();
if (!this.storeByType.ContainsKey(key)) {
// ... add new List<T> instantiated by reflection
// use MakeGenericType + Activator.CreateInstance for example
}
// cast to the non-generic interface
var list = (IList)this.storeByType[key];
list.Add(p);
}
}
Note, that the code is just present as an example to demonstrate the idea, missing many checks and safety, and might not even work as is.
I would keep a dictionary inside the VendingMachine that holds the snacks of different types with the type as the key. By doing so you avoid having to search a list with mixed types every time you want to fetch the items.
static void Main(string[] args)
{
var m = new VendingMachine();
m.AddRange(new Drink(), new Drink());
m.AddRange(new Sweet());
var drinks = m.Fetch<Drink>();
var sweets = m.Fetch<Sweet>();
}
public class VendingMachine
{
private readonly Dictionary<Type, List<Snack>> _snacks = new();
public void AddRange<T>(params T[] snacks) where T : Snack
{
var type = typeof(T);
if (_snacks.TryGetValue(type, out var existingSnacks))
existingSnacks.AddRange(snacks);
else
_snacks.Add(type, new List<Snack>(snacks));
}
public List<T> Fetch<T>() where T : Snack
{
if (_snacks.TryGetValue(typeof(T), out var existingSnacks))
return new List<T>(existingSnacks.Cast<T>());
return new List<T>();
}
}
I think maybe there's a different way of doing this. With your base SnackBase base class and derived Drink and Sweet classes, you can fill a VendingMachine class with snacks then get the drink and sweet lists from the vending machine. The code below illustrates this:
Base Class
internal class SnackBase
{
public string Name { get; }
protected SnackBase(string name)
{
if (string.IsNullOrWhiteSpace(name))
throw new ArgumentOutOfRangeException(nameof(name));
Name = name;
}
}
Derived classes
internal class Drink : SnackBase
{
public Drink(string name) : base(name) {}
}
internal class Sweet : SnackBase
{
public Sweet(string name) : base(name) {}
}
VendingMachine.cs
internal class VendingMachine
{
private readonly List<SnackBase> _snacks;
public VendingMachine(List<SnackBase> snacks)
{
_snacks = snacks;
}
public List<SnackBase> GetDrinks()
{
return _snacks.Where(s => s.GetType().Name == nameof(Drink)).ToList();
}
public List<SnackBase> GetSweets()
{
return _snacks.Where(s => s.GetType().Name == nameof(Sweet)).ToList();
}
}
Program.cs
internal static class Program
{
public static void Main()
{
var snacks = new List<SnackBase>
{
new Drink("Coke"),
new Sweet("Snickers"),
new Drink("Pepsi"),
new Sweet("Mars Bar"),
new Drink("7 Up"),
new Sweet("Reece's Pieces")
};
var vendingMachine = new VendingMachine(snacks);
Console.WriteLine("Drinks");
Console.WriteLine("------");
var drinks = vendingMachine.GetDrinks();
foreach (var drink in drinks)
{
Console.WriteLine(drink.Name);
}
Console.WriteLine("Sweets");
Console.WriteLine("------");
var sweets = vendingMachine.GetSweets();
foreach (var sweet in sweets)
{
Console.WriteLine(sweet.Name);
}
}
}
The vending machine class only needs one list of the common type (Snack)
Snacks
public abstract class Snack
{
protected Snack(string name)
{
Name = name;
}
public string Name { get; }
public abstract override string ToString();
}
public class Sweet : Snack
{
public Sweet(string name) : base(name)
{
}
public override string ToString() => $"Sweet({Name})";
}
public class Drink : Snack
{
public Drink(string name) : base(name)
{
}
public override string ToString() => $"Drink({Name})";
}
Vending Machine
public class VendingMachine
{
readonly List<Snack> _snacks;
public VendingMachine(params Snack[] snacks) => _snacks = new List<Snack>(snacks);
public VendingMachine(IEnumerable<Snack> snacks) => _snacks = new List<Snack>(snacks);
public IReadOnlyList<Snack> Snacks { get => _snacks; }
public IReadOnlyList<Drink> Drinks { get => _snacks.OfType<Drink>().ToList(); }
public IReadOnlyList<Sweet> Sweets { get => _snacks.OfType<Sweet>().ToList(); }
public void AddDrink(string name) => _snacks.Add(new Drink(name));
public void AddSweet(string name) => _snacks.Add(new Sweet(name));
}
Test Program
static class Program
{
static void Main(string[] args)
{
var vend = new VendingMachine();
vend.AddDrink("Joke Cola");
vend.AddSweet("Mersa Bar");
vend.AddDrink("Diet Goo");
vend.AddDrink("Bronto Care");
vend.AddSweet("Broken Tooth");
Console.WriteLine("Vending Machine Sweets");
foreach (var item in vend.Sweets)
{
Console.WriteLine(item);
}
Console.WriteLine();
Console.WriteLine("Vending Machine Drinks");
foreach (var item in vend.Drinks)
{
Console.WriteLine(item);
}
}
}
Sample Output
Vending Machine Sweets
Sweet(Mersa Bar)
Sweet(Broken Tooth)
Vending Machine Drinks
Drink(Joke Cola)
Drink(Diet Goo)
Drink(Bronto Care)
Assuming that doing typecasting isn't viable for performance reasons:
public class ai_task
{
public virtual TaskStatus StartTask(Base_NPC mRef) { return TaskStatus.STARTED; }
public virtual TaskStatus RunTask(Base_NPC mRef) { return TaskStatus.RUNNING; }
public virtual void EndTask(Base_NPC mRef) { }
}
Say we have this base class for all NPCs and we want to get around to making different tasks for different types of NPCs.
This is what I have:
public class Shoot_Target : ai_task
{
public TaskStatus StartTask(Shooter_NPC mRef)
{
//Shoot target, pew pew
return base.StartTask(mRef);
}
}
Is this the best way to go about handling it?
And if not, what is the best approach?
Keep in mind the functions are virtual in ai_task because I may want to create generic tasks that can be applied to all NPCs.
Turns out generics were the answer.
Here is a test snippet that I put in another program:
//Parent class
public class Animal
{
public virtual void Speak()
{
Console.WriteLine("I'm an animal, I don't speak");
}
}
//Child class
public class Human : Animal
{
public override void Speak()
{
Console.WriteLine("I'm a more evolved animal. I DO speak.");
}
public void InventStuff()
{
Console.WriteLine("And also as a human I can do things like invent tools.");
}
}
public enum TaskStatus
{
STARTED = 0,
RUNNING,
COMPLETE,
FAIL
}
public class ai_task<T>
{
public virtual TaskStatus StartTask(T mRef) { return TaskStatus.STARTED; }
}
public class Speak_Task : ai_task<Animal>
{
public override TaskStatus StartTask(Animal mRef)
{
mRef.Speak();
return base.StartTask(mRef);
}
}
public class Invent_Task : ai_task<Human>
{
public override TaskStatus StartTask(Human mRef)
{
mRef.InventStuff();
return base.StartTask(mRef);
}
}
Below snippet for output:
var man = new Human();
var dog = new Animal();
var spktask = new Speak_Task();
var invtask = new Invent_Task();
Console.WriteLine(spktask.StartTask(man));
Console.WriteLine(spktask.StartTask(dog));
Console.WriteLine(invtask.StartTask(man));
I have a lot of classes that store different types of data but manipulate the data differently. Is there someway I can abstract what class I'm using...and just call the class's methods? I will have one object that I'm using at a given moment, masterclass.
For example I have class1 and class2. Both classes can do .add .subtract...etc.
I want to say...masterclass is now class1. So I can do masterclass.add instead of class1.add. Then change masterclass to class2 and do a masterclass.subtract instead of class1.subtract.
Ok...maybe this is clearer:
class cat
{
String legs="4 legs";
String claws="cat has lots of claws";
public string GetLegs()
{ return legs+claws;
}
}
class bird
{
String legs="2 wings";
String talons="Bird has 2 talons";
public string GetLegs()
{ return legs+talons;
}
}
class animal;
mainfunction()
{
string temp;
animal = cat;
temp = animal.GetLegs();
animal = bird;
temp = animal.getLegs();
}
You could do it in several ways, either you use interfaces, and implement it like for example:
public interface ICalculate {
void Add();
void Subtract();
}
and implement your classes in such a way that they inherit from the interface, like so:
public class SpecificClass : ICalculate {
public void Add() {
// ...
}
public void Subtract() {
// ...
}
}
public class OtherSpecificClass : ICalculate {
public void Add() {
// ...
}
public void Subtract() {
// ...
}
}
or you can use an abstract base class like:
public abstract class AbstractCalculate {
public abstract void Add();
public abstract void Subtract();
}
and implement specific classes like:
public class SpecificCalculate : AbstractCalculate {
public override void Add() {
// ...
}
public override void Subtract() {
// ...
}
}
in the first example you can create your specific classes like:
ICalculate calc1 = new SpecificCalculate();
and call
calc1.Add();
in the second one one, you can use
AbstractCalculate calc11 = new SpecificCalculate();
and call
calc1.Add();
both have a similar way of working, both have their advantages
more info you can find for example on MSDN
Per suggestion of Ed Plunkett, you could have then for example following implementations (lets say for the ICalculate version)
IList<ICalculate> calculations = new List<ICalculate>();
// <-- add specific instances to the list
calculations.Add( new SpecificClass() );
calculations.Add( new OtherSpecificClass() );
// iterate the list
foreach (var calculation in calculations) {
calculation.Add();
}
or to be more specific to your updated question
public interface IAnimal {
int GetLegs();
}
public class Bird : IAnimal {
public int GetLegs() {
return 2;
}
}
public class Cat : IAnimal {
public int GetLegs() {
return 4;
}
}
and the program would use it like
class Program {
static int GetLegs(IAnimal animal) {
return animal.GetLegs();
}
static void Main(string[] args) {
Cat cat = new Cat();
Bird bird = new Bird();
Console.WriteLine( GetLegs( bird ) ); // 2
Console.WriteLine( GetLegs( cat ) ); // 4
}
}
Or like
IList<IAnimal> animals = new List<IAnimal>();
animals.Add( new Cat() );
animals.Add( new Bird() );
int totalLegs = 0;
foreach (var animal in animals) {
totalLegs += animal.GetLegs(); // or totalLegs += GetLegs( animal );
}
Console.WriteLine( totalLegs ); // 6
This is what I want to do in C# (within class Helper - without generic arguments),
List<AbstractClass<dynamic>> data;
public void Add<T>(AbstractClass<T> thing)
{
this.data.Add((AbstractClass<dynamic>) thing);
}
This helper class would take and work with AbstractClass<> objects and give back AbstractClass<> of specific generic type. AbstractClass<T> contains many functions which return T / take in T like public T Invoke().
For Helper class T cannot be known beforehand. The Add<T>(.. thing) function is not in a class of type T.
To be used like this in Helper class's functions,
foreach(var c in data.Where(x => ...))
{
// public T Invoke() { ... } function within AbstractClass<T>
var b = c.Invoke();
// logic
}
This also fails,
List<AbstractClass<object>> data;
public void Add<T>(AbstractClass<T> thing)
{
this.data.Add((AbstractClass<object>) thing);
}
Now I think I can have,
List<dynamic> data; // or List<object> data;
public void Add<T>(AbstractClass<T> thing)
{
this.data.Add(thing);
}
but I want the constraint that List named data has only elements of type like
ConcreteClass : AbstractClass<OtherClass>
So we would know that there is an public T Invoke() function but we do not know what it returns. This is helpful to avoid mistakes of say misspelling Invocke and only knowing at run-time.
I want to avoid casting to dynamic every time to invoke functions that give back generic type T
To do what you want to do you are going to need to use a Contravariant interface
public class Program
{
static void Main()
{
var m = new Helper();
m.Add(new ConcreteClass());
m.Process();
}
class Helper
{
List<IAbstractClass<OtherClassBase>> data = new List<IAbstractClass<OtherClassBase>>();
public void Add(IAbstractClass<OtherClassBase> thing)
{
this.data.Add(thing);
}
public void Process()
{
foreach(var c in data.Where(x => x.ShouldBeProcessed()))
{
var b = c.Invoke();
Console.WriteLine(b.Question);
var castData = b as OtherClass;
if (castData != null)
Console.WriteLine(castData.Answer);
}
}
}
public interface IAbstractClass<out T>
{
bool ShouldBeProcessed();
T Invoke();
}
abstract class AbstractClass<T> : IAbstractClass<T>
{
public bool ShouldBeProcessed()
{
return true;
}
public abstract T Invoke();
}
class ConcreteClass : AbstractClass<OtherClass>
{
public override OtherClass Invoke()
{
return new OtherClass();
}
}
class OtherClassBase
{
public string Question { get { return "What is the answer to life, universe, and everything?"; } }
}
class OtherClass : OtherClassBase
{
public int Answer { get { return 42; } }
}
}
You do not need to tell Add what kind of class you are passing it, all that matters is it derives from the type specified. You could do public void Add(IAbstractClass<object> thing) and every class would work, but Invoke() would only return objects inside the foreach loop.
You need to figure out what is the most derived class you want Invoke() to return and that is what you set as the type in the list.
Maybe this will work for you:
public class Program
{
static void Main()
{
var m1 = new Helper<OtherClass>();
m1.Add(new ConcreteClass());
var m2 = new Helper<int>();
m2.Add(new ConcreteClass2());
}
class Helper<T>
{
List<AbstractClass<T>> data = new List<AbstractClass<T>>();
public void Add<T1>(T1 thing) where T1 : AbstractClass<T>
{
this.data.Add(thing);
}
}
class AbstractClass<T> { }
class OtherClass { }
class ConcreteClass : AbstractClass<OtherClass> { }
class ConcreteClass2 : AbstractClass<int> { }
}
Let's consider I want to create the following hierarchy:
Animal -> Class (mammal, amphibian, ...) -> Family (Felidae, Canidae, ...) -> Species (cat, tiger, ...).
each sub class dependes on the previous one.
Any suggestion on the best methodology for creating a tree-like class similar to this one?
This is just an example of the problem I have at hands but a solution would help me a lot...
thanks
The real problem is this:
I have to parse a message of the following type 0102060800FF.
Firstly, 01 tells me I have a specific type of message.
Given that type, i must look for the value 02 in a specific table, and so on...
I want a subhierarchy's possible values filtered by its parent. I'm not sure if i'm being clear enough.
thanks
These days, favor composition over inheritance. Here's an example - needs some more logic checking to make sure you're adding into the proper hierarchy, etc.
public class Class
{
private readonly IList<Animal> animals = new List<Animal>();
public IEnumerable<Animal> Animals
{
get
{
return this.animals;
}
}
public void AddAnimal(Animal animal)
{
if (animal == null)
{
throw new ArgumentNullException("animal");
}
this.animals.Add(animal);
}
//// etc.
}
public class Family
{
private readonly IList<Animal> animals = new List<Animal>();
public IEnumerable<Animal> Animals
{
get
{
return this.animals;
}
}
public void AddAnimal(Animal animal)
{
if (animal == null)
{
throw new ArgumentNullException("animal");
}
this.animals.Add(animal);
}
//// etc.
}
public class Species
{
private readonly IList<Animal> animals = new List<Animal>();
public IEnumerable<Animal> Animals
{
get
{
return this.animals;
}
}
public void AddAnimal(Animal animal)
{
if (animal == null)
{
throw new ArgumentNullException("animal");
}
this.animals.Add(animal);
}
//// etc.
}
public class Animal
{
private readonly Class #class;
private readonly Family family;
private readonly Species species;
public Animal(Class #class, Family family, Species species)
{
if (#class == null)
{
throw new ArgumentNullException("#class");
}
if (family == null)
{
throw new ArgumentNullException("family");
}
if (species == null)
{
throw new ArgumentNullException("species");
}
this.#class = #class;
this.family = family;
this.species = species;
this.#class.AddAnimal(this);
this.family.AddAnimal(this);
this.species.AddAnimal(this);
}
public Class Class
{
get
{
return this.#class;
}
}
public Family Family
{
get
{
return this.family;
}
}
public Species Species
{
get
{
return this.species;
}
}
}
Every class down to the actual animal is an abstract class. Tiger is a concrete class which inherits from abstract class Felidae, from abstract class Mammalia, etc.
If you want to get really fancy, you can use interfaces, like IPredator, IWarmBlooded; define them as capabilities.