InvalidCastException when casting from base class to inherited class? - c#

public abstract class ContentManagedEntity
{
public Guid Guid { get; set; }
public bool Active;
public int DisplayOrder;
}
public class StoreCategory : ContentManagedEntity
{
public string Name { get; set; }
}
public class XMLStoreCategory : StoreCategory, IXMLDataEntity
{
public bool Dirty = false;
}
void main() {
var storecategory = new StoreCategory { Name = "Discount Stores" };
var xmlstorecategory = (XMLStoreCategory) storecategory; // Throws InvalidCastException
}
Is there a reason it throws an InvalidCastException at runtime on the last line?
(Bah, as I wrote this, the answer popped into my head, clear as day. Posting it up for posterity, and just to make sure I have it right.)

You're asking this:
class Animal { }
class Cat : Animal { }
class ShortHairedCat : Cat { }
ShortHairedCat shortHairedCat = (ShortHairedCat)new Cat();
Is a Cat a ShortHairedCat? Not necessarily. In this particular case, new Cat() is a Cat that is not a ShortHairedCut so of course you get a runtime exception.
Remember, inheritance models is a relationships. It is not necessarily the case that a Base is a Derived, so in general, "downcasting" is dangerous.

All XMLStoreCategory objects are StoreCategorys, but not all StoreCategorys are XMLStoreCategorys. In this case you're creating a StoreCategory and trying to cast it into something it's not.

You instantiated the object as StoreCategory. It's not the same as XMLStoreCategory, so you can't cast it that way.
The case where the cast would work is something like this:
StoreCategory storecategory = new XMLStoreCategory { Name = "Discount Stores" };
var xmlstorecategory = (XMLStoreCategory) storecategory;
That will work, but in your particular case is somewhat useless. Just instantiate XMLStoreCategory and you'll be good to go.

Related

How to save differently-typed values without converting them and thus losing their specific fields/methods in C#?

I'm trying out C# for the first time, so I apologize if this has a simple solution or if the language simply does not allow it.
I'll simplify my problem to the best of my ability - Imagine I have the following classes:
public class Animal
{
public bool isAlive = true;
public List<Animal> friends;
}
public class Dog : Animal
{
public string Bark()
{
return "Woof!";
}
}
public class Cat : Animal
{
public bool hatesMe = true;
}
public class GoldenRetriever : Dog
{
public bool greatForFamilies = true;
}
Now, the following code:
var Chuck = new GoldenRetriever();
var Stripey = new Cat();
Chuck.friends.Add(Stripey);
var myVar1 = Stripey.hatesMe; //fine
var myVar2 = Chuck.friends[0].hatesMe; //error
I know that when I added Stripey to Chuck's friends list, Stripey was converted to an Animal and lost its Cat members - my problem is: how can I have a list/array/collection of different types, without them losing their specific members?
Thanks in advance!
Actually you are not losing any Data, while storing it in its base type. To access the given data, you need to convert it to the data type which inherits the base type. In your case you need to cast it to Cat in order to access the hatesMe field. This would look something like the code below.
var myVar2 = ((Cat)Chuck.friends[0]).hatesMe;
In simple words, when storing an object in a datatype which it implements or inherits, you are only hiding its other members.
Twenty is right. You need need cast the class Animal to Cat before you can access the 'hatesMe' field:
var myVar2 = ((Cat)Chuck.friends[0]).hatesMe;
But if the type of Animal is unknown you could work with virtual/override properties:
public class Animal
{
public bool isAlive = true;
public List<Animal> friends;
public virtual bool HatesMe
{
get
{
return false;
}
}
}
public class Dog : Animal
{
public string Bark()
{
return "Woof!";
}
}
public class Cat : Animal
{
public override bool HatesMe
{
get
{
return true;
}
}
}
public class GoldenRetriever : Dog
{
public bool greatForFamilies = true;
}
Now the property 'HatesMe' works with all classes which are inherited from Animal:
var Chuck = new GoldenRetriever();
var Stripey = new Cat();
Chuck.friends.Add(Stripey);
var myVar1 = Stripey.hatesMe; //fine
var myVar2 = Chuck.friends[0].HatesMe; //fine
In case the type of Animal is unknown but the given class structure shouldn't be touched you could access the 'hatesMe' field through reflection using the dynamic keyword:
dynamic Stripey = new Cat();
bool b = Stripey.hatesMe; //fine
Be aware, accessing fields through reflection is slow. Furthermore if you rename the 'hatesMe' field without adapting the dynamic code, the code will throw an exception.

Is it possible to restrict the type of variable passed to a .NET method to not be a derived class?

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)

Casting to a generic interface [duplicate]

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

Can an upcasted object be downcasted again without trying a cast for every derived class type of the base class type?

I have case where am given a collection of objects that all derive from the same base class. If I iterate over the collection and check each item's type, I can see that the object is of a derived type and then handle it accordingly. What I would like to know is if there is an easier way of performing the check for the derived type besides what I am already doing. Code repetition typically isn't required, so my current methodology seems a bit off to me.
class A {}
class B : A {}
class C : A {}
class D : C {}
class Foo
{
public List<A> Collection { get; set; }
}
class Bar
{
void Iterate()
{
Foo f = new Foo();
foreach(A item in f.Collection)
{
DoSomething(a);
}
}
void DoSomething(A a)
{
...
B b = a as B;
if(b != null)
{
DoSomething(b);
return;
}
C c = a as C;
if(c != null)
{
DoSomething(c);
return;
}
D d = a as D;
if(d != null)
{
DoSomething(d);
return;
}
};
void DoSomething(B a){};
void DoSomething(C a){};
void DoSomething(D a){};
}
I am working with a web service where every web service must have the same result type.
class WebServiceResult
{
public bool Success { get; set; }
public List<Message> Messages { get; set; }
}
class Message
{
public MessageType Severity { get; set; } // Info, Warning, Error
public string Value { get; set; } //
}
class InvalidAuthorization: Message
{
// Severity = MessageType.Error
// Value = "Incorrect username." or "Incorrect password", etc.
}
class InvalidParameter: Message
{
// ...
}
class ParameterRequired: InvalidParameter
{
// Severity = MessageType.Error
// Value = "Parameter required.", etc.
public string ParameterName { get; set; } //
}
class CreatePerson: Message
{
// Severity = MessageType.Info
// Value = null
public int PersonIdentifier { get; set; } // The id of the newly created person
}
The goal is that we can return as many different types of messages back to the client as we want. Instead of getting a single message per web service call, the callee can know about all of their mistakes/successes in a single trip and to eliminate string parsing specific information from the message.
I originally though about using generics, but since the web service could have varying message types, the collection was broadened to use the base message class.
It may be possible to move DoSomething to A and have each subclass provide their own implementation:
public abstract class A
{
abstract void DoSomething();
}
void Iterate()
{
Foo f = new Foo();
foreach(A item in f.Collection)
{
item.DoSomething();
}
}
An idea would be to use a generic constraint on your base class or an interface.
public class MyClass<T> where T : BaseClass, IInterface
{
public void executeCode<T>(T param) {};
}
So MyClass<T> takes only a certain type, executeCode will have an idea what methods are exposed and what operations can be performed on the data of the object passed.
This avoids the need to cast because you are specifying a contract that must be followed.
typeof(ParentClass).IsAssignableFrom(typeof(ChildClass));
Return true is the cast is possible.
Also possible this way:
typeof(ParentClass).IsAssignableFrom(myObject.GetType());
But in your example, you actually call a methods for each object type. So you would need the cast anyway, unless you don't mind refactoring to not have a collection of overload.
Something like this if you want to keep the overload:
foreach(A item in f.Collection)
{
Type itemType = item.GetType();
if (typeof(B).IsAssignableFrom(itemType)
DoSomethingB(item);
else if (typeof(C).IsAssignableFrom(itemType)
DoSomethingC(item);
//...
}
EDIT: I like more Lee's answer. Adding virtual/override function to the class type would be a better design and way easier to handle, unless the DoSomething really has nothing to do being in the classes.
Lee is right. Just let the item decide, what to do. It knows it's type best and therefore knows what to do. You might even give some standard implementation, if it is the same as in A, by not making it abstract, but virtual. Be aware though, that the compiler wont ask for an implementation then.
public class A
{
public virtual DoSomething(){"What A needs doning!"}
}
public class B : A
{
public override DoSomething() {"What B needs doing!"}
}
Another way would be the use of Interfaces.
public interface IAinterface
{
void DoSomething();
}
public class A : IAinterface
{
void DoSomething(){...}
}
public class B : IAinterface
{
void DoSomething(){...}
}
This would be more like Lees suggestion, although interfaces and abstract base classes work a bit different in the background.
I usually prefer the upper one, because I usually tend to give the base class some standard behavior and only implement derived classes, when there is something different.

Elegant Dynamic Type Casting

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 };
}
}

Categories

Resources