I'd appreciate your advice on the following:
I'm using polymorphism. I have a base class and 30 sub classes that inherit this base class. I'm up casting instances of these sub classes to the base class type so that they can be handled in a more generic fashion.
My question is this.
I need to access a public property that is specific to a particular sub class. Do I need to write a giant case statement where I check the type and down cast accordingly in order to access the property I need or is there a more elegant solution?
static void Main(string[] args)
{
animal slyvester = new cat();
animal lassie = new dog();
animal silver = new horse();
// Big ugly type checking code. If I have 30 types to check is there a better way?
if (slyvester.GetType() == typeof(cat)) {
Console.WriteLine(((cat)(animal)slyvester).PurrStrength);
}
else if(slyvester.GetType() == typeof(dog)) {
}
else if (slyvester.GetType() == typeof(horse))
{
}
Console.ReadLine();
}
}
public class animal {
}
public class cat : animal {
private string _purrStrength = "Teeth Shattering";
public string PurrStrength {
get { return _purrStrength; }
set { _purrStrength = value; }
}
}
public class dog : animal {
}
public class horse : animal {
}
You should consider an interface based approach. With interfaces, you define a set of operations (a contract by which implementers must conform) which your types must define. E.g, we could define a base interface, IAnimal
public interface IAnimal
{
string GetSound();
}
From which we can define some animal types:
public class Cat : IAnimal
{
public string GetSound()
{
return "Meow!";
}
}
public class Dog : IAnimal
{
public string GetSound()
{
return "Woof!";
}
}
Now, when we want to declare our animal, we declare it of type IAnimal:
IAnimal cat = new Cat();
IAnimal dog = new Dog();
Console.WriteLine(cat.GetSound());
Console.WriteLine(dog.GetSound());
You could go one step further, and specialise your animals:
public class Cat : IAnimal
{
public virtual string GetSound()
{
return "Meow!";
}
}
public class BigCat : Cat
{
public override string GetSound()
{
return "Roar!";
}
}
In the latter example, I can make a default implementation of the cat's GetSound method, and then override it for my big cat.
Interface based programming hides away the need to horrible type conversions, because an interface guarantees a set of operations that will be provided.
If you don't have to know the exact type of the passed object, you just need a property value in case it doesn't exist in the base type, but it may or may not exists in the actual type, you can use reflection:
static void Main(string[] args)
{
animal slyvester = new cat();
animal lassie = new dog();
animal silver = new horse();
DoSomething(slyvester);
DoSomething(lassie);
DoSomething(silver);
Console.ReadLine();
}
static void DoSomething(animal entity)
{
string INeedThisProperty = "PurrStrength";
Type type = entity.GetType();
PropertyInfo property = type.GetProperty(INeedThisProperty);
if (property != null && property.CanRead)
{
Console.WriteLine("Found: {0}", property.GetValue(entity, null));
}
}
If in precise moment of property access you dont't have any clue what type is it, somehow you have to figure out it.
Or, what I personaly would do, is try to create virtual functions/properties on base class that describes my child classes action in more generic way, override them in child classes with concrete implementation and after call that functions/properties using upper casted objects.
The answer is to use polymorphism. The idea is to introduce a method in the base interface or as in this case the base class. Then just call this method! The runtime will automagically delegate the call to the correct type.
Look at the modified implementation below:
public abstract class Animal
{
public abstract void OutputInterestingFact();
}
public class Cat : Animal {
private string _purrStrength = "Teeth Shattering";
public string PurrStrength {
get { return _purrStrength; }
set { _purrStrength = value; }
}
public override void OutputInterestingFact()
{
Console.WriteLine(PurrStrength);
}
}
public class Dog : Animal {
public override void OutputInterestingFact()
{
// Do stuff for dog here
}
}
public class Horse : Animal {
public override void OutputInterestingFact()
{
// Do stuff for horse here
}
}
I made the Animal into an abstract class. You could also make the OutputInterestingFact method virtual with an empty method body.
I've also renamed your classes to begin with an upper case letter. Make this a habit since this is practice in C# and other programmers will find your code easier to read.
Now, to use this just call the method.
slyvester.OutputInterestingFact();
Is that elegant enough?
Your code does not cover all the cases that I can think of, but just 2 possible solutions:
class Animal {
public abstract string PropertyValue { get; set; }
}
class Cat : Animal {
public override string PropertyValue {
get { return PurrStrength; }
set { PurrStrength = value; }
}
}
or, for multiple properties:
class Animal {
public virtual string[] GetPropertyValues() { return null; }
}
class Cat : Animal {
public override string[] GetPropertyValues() {
return new string[] { PurrStrength };
}
}
Related
I am a C# beginner. I hope you have patience with me. Lets say I have an enum
public enum Dogs
{
Terrier,
Poodle,
Pitbull,
}
and some dog classes
public class Terrier {
}
public class Poodle {
}
public class Pitbull {
}
And I for some reason want to instantiate each of the classes dynamically from their types (enum values),
foreach(Dogs d in Enum.GetValues(typeof(Dogs)))
{
// d myDog = new d();
// "...is a variable but is used like a type"
}
I have also tried with
var myDog = Activator.CreateInstance(d);
// "...cannot convert from namespace.Dogs to System.Type"
If you really want it:
(typeof(Dogs)).Assembly.CreateInstance(d.ToString());
Don't use an enum for that. A much saner solution is an array of Types:
private static Type[] dogs =
{
typeof(Terrier),
typeof(Poodle),
typeof(Pitbull),
}
Then you can still go over them all:
foreach (Type type in dogs)
{
Object dog = Activator.CreateInstance(type);
}
Though unless you're only using .ToString() on it, you might want to give those classes a common interface or superclass to inherit (as rfmodulator also said in his answer) so you can actually call functions on the resulting objects. If all three inherit from a Dog superclass, which makes them share a common Bark() method, you can at least do something like this:
public abstract class Dog
{
String Bark();
}
public class Terrier : Dog
{
public override String Bark() { return "Woof!"; }
}
public class Poodle : Dog
{
public override String Bark() { return "Yap"; }
}
public class Pitbull : Dog
{
public override String Bark() { return "Whuff!"; }
}
...so you can actually get something useful out of your instantiated objects:
foreach (Type type in dogs)
{
Dog dog = (Dog)Activator.CreateInstance(type);
Console.WriteLine(dog.Bark());
}
The only slight downside to this method, from a design perspective, is that there's no way to enforce that only sub-types of Dog can be put in the Type[] dogs array; technically, any type object can be put in there. So that's the programmer's responsibility to not mess that up.
Dogs.Terrier is a different thing than Terrier.
Here is how you could do something like you're describing:
For simplicity, I'm going to make all the classes implement a common interface, IDog:
public interface IDog { }
public class Terrier : IDog
{
}
public class Poodle : IDog
{
}
public class Pitbull : IDog
{
}
Now we can do this:
IDog dog;
foreach (Dogs d in Enum.GetValues(typeof(Dogs)))
{
switch (d)
{
case Dogs.Terrier:
dog = new Terrier();
break;
case Dogs.Poodle:
dog = new Poodle();
break;
case Dogs.Pitbull:
dog = new Pitbull();
break;
default:
throw new Exception("no such dog!");
}
Debug.WriteLine($"dog is {dog.GetType()}");
}
Can i constrain the type that is passed to my method in a way that catches this type of error when compiling instead of running?
My current code looks like this:
void Main()
{
var dog = new Dog();
SaveAnimal(dog);
}
void SaveAnimal(Animal animal) {
var isAnimal = animal.GetType().UnderlyingSystemType == typeof(Animal);
Debug.Assert(isAnimal, "You can not save dogs!");
}
class Animal {
public int Legs { get; set; }
}
class Dog : Animal {
public int TailLength { get; set; }
}
No, there is no way in the language to statically catch this as a usage error.
You can assert this at runtime as you are doing it already. It's against the spirit of inheritance, though, because a fundamental assumption is that derived types must substitute for the base type (the Liskov substitution principle).
Maybe you can make the animal save itself by giving Animal a new method abstract void Save(). Then, each animal decides what to do. Dog can then throw a NotSupportedException.
Yes, but only with a workaround using generics and interfaces.
What you would need to do is to declare 3 interfaces
public interface ISaveAbleBase { }
public interface ISaveAble : ISaveAbleBase{ }
public interface INotSaveAble : ISaveAbleBase { }
Now you need to give your Animal class a generic parameter and constraint it to be of type ISaveAbleBase.
class Animal<T> where T: ISaveAbleBase
{
public int Legs { get; set; }
}
This way you can now specify in the derived classes wether they can or cannot be saved:
class Dog : Animal<INotSaveAble>
{
public int TailLength { get; set; }
}
Then you could make your method generic and constrain the type only to aminals that can be saved
void SaveAnimal<T>(T animal) where T: Animal<ISaveAble>
Now the result looks the following way:
void Main()
{
var dog = new Dog();
SaveAnimal(dog); // does not compile
Animal<ISaveAble> generalAnimal = new Animal<ISaveAble>();
SaveAnimal(generalAnimal); // compiles
}
Disclaimer: this construct would also allow you to have a general Animal that cannot be saved:
Animal<INotSaveAble> generalAnimalNotSave = new Animal<INotSaveAble>();
SaveAnimal(generalAnimalNotSave); // does not compile
PS. This answer is inspired by this post
There is no standard way how to do this, but there is a simple (and stupid) workaround.
using System.Diagnostics;
namespace Test
{
internal static class Program
{
private static void Main()
{
var dog = new Dog();
SaveAnimal(dog);
}
private static void SaveAnimal(Animal animal)
{
var isAnimal = animal.GetType().UnderlyingSystemType == typeof(Animal);
Debug.Assert(isAnimal, "You can not save dogs!");
}
private static void SaveAnimal(ICanNotSave animal)
{
Debug.Fail("Can not save");
}
}
internal class Animal
{
public int Legs
{
get; set;
}
}
internal interface ICanNotSave
{
}
internal sealed class Dog : Animal, ICanNotSave
{
public int TailLength
{
get; set;
}
}
}
When you have two SaveAnimal method, where one of for Animal and other is for a interface, that is implemented on all descendants that can not be saved, the compiler report a CS0121 error.
The call is ambiguous between the following methods or properties: 'Program.SaveAnimal(Animal)' and 'Program.SaveAnimal(ICanNotSave)'
Remember it is still possible to use the SaveAnimal method when you use it like this: SaveAnimal((Animal)dog)
I have the following classes
public abstract class BaseViewPresenter { }
public abstract class BaseView<T> : UserControl
where T : BaseViewPresenter { }
public class LoginPresenter : BaseViewPresenter { }
public partial class LoginView : BaseView<LoginPresenter> { }
I have a method that looks like this (simplified)
public BaseView<BaseViewPresenter> Resolve(BaseViewPresenter model)
{
var type = model.GetType();
var viewType = _dataTemplates[type];
// Correctly creates BaseView object
var control = Activator.CreateInstance(viewType);
// Fails to cast as BaseView<BaseViewPresenter> so returns null
return control as BaseView<BaseViewPresenter>;
}
When I call this using an instances of LoginPresenter
var login = new LoginPresenter();
var ctl = Resolve(login);
The line Activator.CreateInstance(viewType) correctly resolves into a new instances of my LoginView, however control as BaseView<BaseViewPresenter> can't do the cast correctly so returns null.
Is there a way to correctly cast the control into BaseView<BaseViewPresenter> without using specific type generics?
Since LoginView inherits from BaseView<LoginPresenter>, and LoginPresenter inherits from BaseViewPresenter, I would assume there's a way to convert LoginView to BaseView<BaseViewPresenter>.
I am stuck with using .Net 3.5
This is a very frequently asked question. Let's rename your types:
abstract class Fruit { } // was BaseViewPresenter
abstract class FruitBowl<T> where T : Fruit // was BaseView
class Apple : Fruit { } // was LoginPresenter
class BowlOfApples : FruitBowl<Apple> { } // was LoginView
Your question now is:
I have a BowlOfApples, which inherits from FruitBowl<Apple>. Why can I not use it as a FruitBowl<Fruit>? An apple is a fruit, so a bowl of apples is a bowl of fruit.
No, it isn't. You can put a banana in a bowl of fruit, but you can't put a banana in a bowl of apples, and therefore a bowl of apples is not a bowl of fruit. (And by similar argument, a bowl of fruit is not a bowl of apples either.) Since the operations you can legally perform on the two types are different, they cannot be compatible.
Here is a photo of StackOverflow legend Jon Skeet demonstrating this fact:
The feature you want is called generic contravariance, and it is supported only on interfaces and delegate types when the compiler can prove that the variance is safe, and when the varying type is a reference type. For example, you can use an IEnumerable<Apple> in a context where IEnumerable<Fruit> is needed because the compiler can verify that there is no way that you can put a Banana into a sequence of fruit.
Do a search on "C# covariance and contravariance" on this site or on the web and you'll find many more details about how this feature works. In particular, my series of articles on how we designed and implemented this feature in C# 4 starts here: http://blogs.msdn.com/b/ericlippert/archive/2007/10/16/covariance-and-contravariance-in-c-part-one.aspx
I accepted Eric's answer since it provides a great explanation of why what I wanted wasn't possible, but I also thought I'd share my solution in case anyone else runs into this same problem.
I removed the generic type parameter from my original BaseView class, and created a 2nd version of the BaseView class that included the generic type parameter and specifics for it.
The first version is used by my .Resolve() method or other code that doesn't care about the specific types, and the second version is used by any code that does care, such as the implentation of a BaseView
Here's an example of how my code ended up looking
// base classes
public abstract class BaseViewPresenter { }
public abstract class BaseView : UserControl
{
public BaseViewPresenter Presenter { get; set; }
}
public abstract class BaseView<T> : BaseView
where T : BaseViewPresenter
{
public new T Presenter
{
get { return base.Presenter as T; }
set { base.Presenter = value; }
}
}
// specific classes
public class LoginPresenter : BaseViewPresenter { }
public partial class LoginView : BaseView<LoginPresenter>
{
// Can now call things like Presenter.LoginPresenterMethod()
}
// updated .Resolve method used for obtaining UI object
public BaseView Resolve(BaseViewPresenter presenter)
{
var type = model.GetType();
var viewType = _dataTemplates[type];
BaseView view = Activator.CreateInstance(viewType) as BaseView;
view.Presenter = presenter;
return view;
}
You're expecting to treat the type as being covariant with respect to the generic argument. Classes can never be covariant; you'd need to use an interface rather than (or in addition to) an abstract class to make it covariant with respect to T. You'd also need to be using C# 4.0.
My usual solution to this problem is to create an intermediary class that has access to the type-parametric class's methods through delegates. Fields can also be accessed through getters/setters.
The general pattern goes:
public abstract class Super {}
public abstract class MyAbstractType<T> where T : Super {
public MyGeneralType AsGeneralType() {
return MyGeneralType.Create(this);
}
// Depending on the context, an implicit cast operator might make things
// look nicer, though it might be too subtle to some tastes.
public static implicit operator MyGeneralType(MyAbstractType<T> t) {
return MyGeneralType.Create(t);
}
public int field;
public void MyMethod1() {}
public void MyMethod2(int argument) {}
public abstract bool MyMethod3(string argument);
}
public delegate T Getter<T>();
public delegate void Setter<T>(T value);
public delegate void MyMethod1Del();
public delegate void MyMethod2Del(int argument);
public delegate bool MyMethod3Del(string argument);
public class MyGeneralType {
public Getter<int> FieldGetter;
public Setter<int> FieldSetter;
public MyMethod1Del MyMethod1;
public MyMethod2Del MyMethod2;
public MyMethod3Del MyMethod3;
public static MyGeneralType Create<T>(MyAbstractType<T> t) where T : Super {
var g = new MyGeneralType();
g.FieldGetter = delegate { return t.field; };
g.FieldSetter = value => { t.field = value; };
g.MyMethod1 = t.MyMethod1;
g.MyMethod2 = t.MyMethod2;
g.MyMethod3 = t.MyMethod3;
return g;
}
public int field {
get { return FieldGetter(); }
set { FieldSetter(value); }
}
}
The above exemplifies getting all the methods and fields but normally I only need a few of them. This is a general solution to the problem and one could feasibly write a tool to generate these intermediary classes automatically, which I might at some point.
Try it here: https://dotnetfiddle.net/tLkmgR
Note that this is enough for all my cases, but you can be extra hacky with this:
public abstract class MyAbstractType<T> where T : Super {
// ... Same everything else ...
// data fields must become abstract getters/setters, unfortunate
public abstract int field {
get;
set;
}
public static implicit operator MyAbstractType<Super>(MyAbstractType<T> t) {
return MyGeneralType.Create(t);
}
}
public class MyGeneralType : MyAbstractType<Super> {
// ... same constructors and setter/getter
// fields but only keep method fields
// that contain the method references for
// implementations of abstract classes,
// and rename them not to clash with the
// actual method names ...
public MyMethod3Del myMethod3Ref;
// Implement abstract methods by calling the corresponding
// method references.
public override bool MyMethod3(string argument) {
return myMethod3Ref(argument);
}
// Same getters/setters but with override keyword
public override int field {
get { return FieldGetter(); }
set { FieldSetter(value); }
}
}
And there you go, now you can literally cast a MyAbstractType<Sub> where Sub : Super to a MyAbstractType<Super>, although it's no longer the same object anymore, but it does retain the same methods and data, it's sort of a complex pointer.
public class Sub : Super {}
public class MySubType : MyAbstractType<Sub> {
public int _field;
public override int field {
get { return _field; }
set { _field = value; }
}
public override bool MyMethod3(string argument) {
Console.WriteLine("hello " + argument);
return argument == "world";
}
}
public class MainClass {
public static void Main() {
MyAbstractType<Sub> sub = new MyAbstractType<Sub>();
MyAbstractType<Super> super = sub;
super.MyMethod3("hello"); // calls sub.MyMethod3();
super.field = 10; // sets sub.field
}
}
This isn't as good in my opinion, the other version of MyGeneralType is a more straighforward layer over the concrete types, plus it doesn't require rewriting the data fields, but it does actually answer the question, technically. Try it here: https://dotnetfiddle.net/S3r3ke
Example
Using these abstract classes:
public abstract class Animal {
public string name;
public Animal(string name) {
this.name = name;
}
public abstract string Sound();
}
public abstract class AnimalHouse<T> where T : Animal {
List<T> animals;
public AnimalHouse(T[] animals) {
this.animals = animals.ToList();
}
public static implicit operator GeneralAnimalHouse(AnimalHouse<T> house) {
return GeneralAnimalHouse.Create(house);
}
public List<string> HouseSounds() {
return animals.Select(animal => animal.Sound()).ToList();
}
}
We make this "general" variant:
public delegate List<string> HouseSoundsDel();
public class GeneralAnimalHouse {
public HouseSoundsDel HouseSounds;
public static GeneralAnimalHouse Create<T>(AnimalHouse<T> house) where T : Animal {
var general = new GeneralAnimalHouse();
general.HouseSounds = house.HouseSounds;
return general;
}
}
And finally with these inheritors:
public class Dog : Animal {
public Dog(string name) : base(name) {}
public override string Sound() {
return name + ": woof";
}
}
public class Cat : Animal {
public Cat(string name) : base(name) {}
public override string Sound() {
return name + ": meow";
}
}
public class DogHouse : AnimalHouse<Dog> {
public DogHouse(params Dog[] dogs) : base(dogs) {}
}
public class CatHouse : AnimalHouse<Cat> {
public CatHouse(params Cat[] cats) : base(cats) {}
}
We use it like this:
public class AnimalCity {
List<GeneralAnimalHouse> houses;
public AnimalCity(params GeneralAnimalHouse[] houses) {
this.houses = houses.ToList();
}
public List<string> CitySounds() {
var random = new Random();
return houses.SelectMany(house => house.HouseSounds())
.OrderBy(x => random.Next())
.ToList();
}
}
public class MainClass {
public static void Main() {
var fluffy = new Cat("Fluffy");
var miu = new Cat("Miu");
var snuffles = new Cat("Snuffles");
var snoopy = new Dog("Snoopy");
var marley = new Dog("Marley");
var megan = new Dog("Megan");
var catHouse = new CatHouse(fluffy, miu, snuffles);
var dogHouse = new DogHouse(snoopy, marley, megan);
var animalCity = new AnimalCity(catHouse, dogHouse);
foreach (var sound in animalCity.CitySounds()) {
Console.WriteLine(sound);
}
}
}
Output:
Miu: meow
Snoopy: woof
Snuffles: meow
Fluffy: meow
Marley: woof
Megan: woof
Notes:
I added names so it's clear that the method references carry their owner's data with them, for those unfamiliar with delegates.
The required using statements for this code are System, System.Collections.Generic, and System.Linq.
You can try it here: https://dotnetfiddle.net/6qkHL3#
A version that makes GeneralAnimalHouse a subclass of AnimalHouse<Animal> can be found here: https://dotnetfiddle.net/XS0ljg
I have 3 projects: 2 are class libraries and 1 is console app:
class library "AnimalManagers". In AnimalManagers is
public interface AnimalAgressiveBase{
string Bark<TAnimal>(TAnimal animal);
}
public abstract class AnimalAgressive<TEnemy> : AnimalAggresiveBase {
public abstract string BarkAtEnemy(TEnemy enemy);
public string Bark<TAnimal>(TAnimal animal){
return BarkAtEnemy((TEnemy)animal);// <---- Invalid cast exception even if type of object "animal" is Cat and we call this method from Dog class
}
}
public class AnimalManager {
public void WatchAnimal<TAnimalModel>
(TAnimalModel animalModel) { //<-- in example, animalModel is Cat("lucy")
var aggresiveAnimalDog = GetAgresiveAnimal(); //<-- returns object from dynamically loaded class Dog so this is basicaly new Dog() if animal models library class were referenced
if(aggresiveAnimalData != null) aggresiveAnimalDog .Bark(animalModel);
}
public AnimalAgressiveBase GetAgresiveAnimal(){
Assembly.LoadFrom("..\\AnimalModels.dll");
....
return aggresiveAnimal; //In This case Dog because he implements correct interface
}
}
class library "AnimalModels" In AnimalModels are model classes Cat and Dog
public class Cat {
public string Name {get;set;}
}
public class Dog : AnimalAgressive<Cat> {
public override string BarkAtEnemy(Cat enemy){return enemy.Name;}
}
Both libraries are referenced in ConsoleApp "Zoo" , and I get invalid type exception when I call
var manager = new AnimalManager();
var manager.WatchAnimal(new Cat{Name="lucy"});
I got invalid cast exception because of dynamically loaded assembly types doesnt coresspond with referenced types, even if they got same AssemblyQualifiedName.
Any solutions? Goal is to load assembly get types that implements known interface (ex: AnimalAggressiveBase) and call method that I pass data of some type.
Your main issue seems to be that you do not have anything representing your animals in the type system. How does your class Cat tie in with the rest of your class hierarchy?
public void WatchAnimal<TAnimalModel>
(TAnimalModel animalModel) { ... }
Basically here TAnimalModel can be anything; I could pass in a string an int or a Stream and the compiler wouldn't complain. You need to constaint TAnimalModel to what you are really expecting so that the compiler can reason about what you can do or not do with animalModel:
public void WatchAnimal<TAnimalModel>
(TAnimalModel animalModel) { ... } where TAnimalModel: AnimalBase
AnimalBase can be an abstract base class, a regular base class, an interface, what have you. The only condition is that all your animal models need to implement it:
public class Cat: AnimalBase { ... }.
The same thing happens with the following method:
public abstract class AnimalAgressive<TEnemy> : AnimalAggresiveBase { ... }
Again, here TEnemy can be anything. That is why you are getting a compile time error in (TEnemy)animal. The compiler can't verify that the cast is valid and therefore disallows it; you know that TEnemy will be an animal but you haven't told the compiler... so tell the compiler adding a constaint:
public abstract class AnimalAgressive<TEnemy> : AnimalAggresiveBase where TEnemy: AnimalBase { ... }
Performance expensive solution IMHO.
[EDIT TO CLASS]
public abstract class AnimalAgressive<TEnemy> : AnimalAggresiveBase where TEnemy : class, new(){
[EDIT TO METHOD]
public string Bark<TAnimal>(TAnimal animal){
var typeAnimal = typeof(TAnimal);
var typeEnemy = typeof(TEnemy);
var propsAnimal = typeData.GetProperties();
var propsEnemy = typeGener.GetProperties();
var obj = new T();
foreach (var propertyInfo in propsAnimal)
{
var value = propertyInfo.GetValue(dataObject);
try
{
var propEnemy = propsEnemy.FirstOrDefault(x => x.Name.Equals(propertyInfo.Name, StringComparison.CurrentCulture));
propGener?.SetValue(obj, value, null);
}
catch (Exception)
{
throw;
}
}
return Bark(obj.Name);
I would recommed MEF here.
public interface IAnimalAgressive<in TAnimal>
{
string Bark(TAnimal animal);
}
public abstract class AnimalAggressiveBase<TEnemy> : IAnimalAgressive<TEnemy>
{
public abstract string BarkAtEnemy(TEnemy enemy);
public string Bark(TEnemy enemy)
{
return BarkAtEnemy(enemy);
}
}
your Animal manager then becomes:
public class AnimalManager
{
public void WatchAnimal<TAggressiveAnimal, TAnimal>
(TAggressiveAnimal aggressive, TAnimal enemy)
where TAggressiveAnimal : IAnimalAgressive<TAnimal>
{
Console.WriteLine(aggressive.Bark(enemy));
}
}
Now its the responsibility of the Dog and Cat to conform to the AnimalManager expectations, I will keep it simple for now:
using System.ComponentModel.Composition;
namespace AnimalModels
{
[Export(typeof(Cat))]
public class Cat
{
public string Name { get; set; }
}
}
and Dog becomes:
using AnimalManagers;
using System.ComponentModel.Composition;
namespace AnimalModels
{
[Export(typeof(AnimalAggressiveBase<Cat>))]
public class Dog : AnimalAggressiveBase<Cat>
{
public override string BarkAtEnemy(Cat enemy)
{
return enemy.Name;
}
}
}
The trick now is to compose the whole catalog of relevant types, so for our console app, we create another type for managing these relationships from the catalog of types we have exported:
public class TypeManager
{
public void Compose()
{
try
{
var directoryPath = Path.GetFullPath(".");
var aggregateCatalog = new AggregateCatalog();
aggregateCatalog.Catalogs.Add(new DirectoryCatalog(directoryPath, "*.dll"));
//Create the composition container
var container = new CompositionContainer(aggregateCatalog);
container.ComposeParts(this);
var cat = container.GetExportedValue<Cat>();
cat.Name = "lucy";
var dog = container.GetExportedValue<AnimalAggressiveBase<Cat>>();
var manager = new AnimalManager();
manager.WatchAnimal(dog, cat);
}
catch (CompositionException compositionException)
{
Console.WriteLine(compositionException.ToString());
throw;
}
}
}
now all we need to do is to run the Main method like this:
static void Main(string[] args)
{
TypeManager tm = new TypeManager();
tm.Compose();
}
Now the exported types will automatically get created in the typemanager and we dont have to worry about reflection.
public interface AnimalAgressiveBase<TAnimal>
{
string Bark(TAnimal animal);
}
public abstract class AnimalAgressive<TEnemy, TAnimal> : AnimalAgressiveBase<TAnimal> where TEnemy : TAnimal
{
public abstract string BarkAtEnemy(TEnemy enemy);
public string Bark(TAnimal animal)
{
return BarkAtEnemy((TEnemy)animal);
}
}
Let there be class NaturalFood and two classes inherit from this class; class Fruits and class Vegetables
abstract class NaturalFood
{
enum AllList
{
//empty list as a placeholder
}
protected string Name;
}
class Fruits : NaturalFood
{
enum AllList
{
Apple = 1,
Banana = 2
}
}
class Vegetables : NaturalFood
{
enum AllList
{
Carrot = 1,
Potatoes = 2
}
}
I want to enforce that any class derived from class NaturalFood must declare and/or override the AllList enumeration. Effectively the enumeration will contain list specific to the derived class. How do I do this ?
Edit: My basic requirement is that each class deriving from a base class must have its own list of "something" that is specific to it. Enumeration is just a way of creating a list. I hope you get the gist from my example. I want to take advantage of what Enumeration offers viz. intellisense, toString() etc.
Edit2: Isn't my example very practical enough ? If I put the entire enumeration in the base class (NaturalFood), how do I know which of the enumerated values are specific to which derived class ? Let us say each derived class is "publishing something" it has to offer in form of enumerated constants and I want to enforce this constraint on every derived class. So in other words, my question is how to enforce a constraint on derived class like in scenario described here ?
Actually, there's no sense to override these values. Actually, the advantages of override is that you can call a method of a derived class without knowing the derived class itself.
For example :
static void Main()
{
NaturalFood food = GetSomeFood(); // At this point, we don't know the actual type
food.SomeMethodInBaseClass(); // ok
}
static NaturalFood GetSomeFood()
{
if(somecondition) {
return new Fruits();
}
else{
return new Vegetables();
}
}
public abstract class NaturalFood
{
public abstract void SomeMethodInBaseClass();
}
public class Fruits : NaturalFood
{
public override void SomeMethodInBaseClass(){
Console.WriteLine("I'm a fruit");
}
}
public class Vegetables : NaturalFood
{
public override void SomeMethodInBaseClass(){
Console.WriteLine("I'm a vegetable");
}
}
No imagine what you wanted to do. In the main method, try to call the AllList :
static void Main()
{
NaturalFood food = GetSomeFood(); // At this point, we don't know the actual type
food.SomeMethodInBaseClass(); // ok
food.AllList.XXXX; // What? it won't compile
}
This won't compile. The compiler has no way to know the actual derived class to infer the available enumeration values.
However, if you remove the enumeration from the base type, this will works :
static void Main()
{
NaturalFood food = GetSomeFood(); // At this point, we don't know the actual type
food.SomeMethodInBaseClass(); // ok
Fruits f = new Fruits();
Console.WriteLine( f.AllList.Apple); // Ok
Vegetable v = new Vegetable ();
Console.WriteLine( v.AllList.Potatoe); // Ok
}
But as you can see, you have to know explicitly the actual type, and thus, make the polymorphic useless.
[Edit] It's hard to answer to your second edit. Actually there are many many ways to validate such constraint. Without more context it may be difficult to answer. The most simple way I think, is to add to each derived class a overriden property that describe what kind of enumeration is accepted.
public enum NaturalFoodType {
Unknown = 0,
Apple= 1,
Banana = 2,
Potatoe = 3,
Cucumber = 4
}
public abstract class NaturalFood
{
public abstract void SomeMethodInBaseClass();
public abstract IEnumerable<NaturalFoodType> AcceptedFoodType { get; }
public bool IsValid(NaturalFoodType type){
return AcceptedFootType.Contains(type);
}
}
public class Fruits : NaturalFood
{
public override void SomeMethodInBaseClass(){
Console.WriteLine("I'm a fruit");
}
public override NaturalFoodType {
get {
yield return NaturalFoodType.Apple;
yield return NaturalFoodType.Banana;
}
}
}
public class Vegetables : NaturalFood
{
public override void SomeMethodInBaseClass(){
Console.WriteLine("I'm a vegetable");
}
public override NaturalFoodType {
get {
yield return NaturalFoodType.Potatoe;
yield return NaturalFoodType.Cucumber;
}
}
}
But honestly, it start to add a lot of plumbing code, that become quite unreadable. You should consider the problem at a higher scope to find an acceptable solution.
This is not possible because enums are types, not class members... and the fact they are declared inside a class doesn't make them members of that class, they are just nested. Every class can and has to define it's own private enum AllList type... so your actual code is the only possible way to go.
If you want to obtain something like this and you have only few values to deal with, stick with properties overrides:
class A
{
public virtual String Value
{
get
{
return "A";
}
}
}
class B : A
{
public override String Value
{
get
{
return "B";
}
}
}