6

Say I have the following classes:

class Animal
{
    public long Id { get; set; }
    public string Name { get; set; }
}

class Dog:Animal
{
    public void sniffBum()
    {
        Console.WriteLine("sniff sniff sniff");
    }
}

If I have an instance of Animal, how do I cast it to a Dog? Something like this:

Animal a = new Animal();
if ( some logic to determine that this animal is a dog )
{
    Dog d = (Dog)a;
    d.sniffBum();
}

Essentially I can't use interfaces. I will always have an Animal object coming out of my database like that. Dog doesn't have any more parameters than Animal has, only new methods.

I could just create a new Dog object, and pass the values across, (or have a constructor that takes a type Animal), but this just seems messy.

Null
  • 1,950
  • 9
  • 30
  • 33
Crudler
  • 2,194
  • 3
  • 30
  • 57

10 Answers10

3

To check whether an object can be cast to a type use the is keyword.

Animal animal = new Dog();

if( animal is Dog)
{
    //your code
}
Hossein Narimani Rad
  • 31,361
  • 18
  • 86
  • 116
  • See msdn docs about is operator http://msdn.microsoft.com/en-us/library/scekt9xw(v=vs.71).aspx The is operator is used to check whether the run-time type of an object is compatible with a given type. – Bogdan M. Apr 25 '13 at 12:49
  • 2
    Didn't do the downvote but i'm pretty sure it's about an animal object being created and then checking if it is a dog, never going to work – JMan Apr 25 '13 at 12:51
  • 1
    -1, as @Jeroen correctly noted, the OPs question is about something else. – Ondrej Tucny Apr 25 '13 at 12:53
  • @OndrejTucny not sure if it is enough reason for -1. – Hossein Narimani Rad Apr 25 '13 at 12:55
  • 1
    I think the point here was to use is operator, to correct the answer you can add var animal = new Dog(); case closed. – Bogdan M. Apr 25 '13 at 12:57
  • 3
    The question states that the Animal comes from a database and then they want to convert it to a Dog -- which means that the is operator will always return false because the instance was CREATED as Animal, and not as Dog. – Dr Herbie Apr 25 '13 at 13:47
3

First create animal as a Dog then check if it is a Dog

Animal a = new Dog();
if (a is Dog )
{
   Dog d = (Dog)a;
   d.sniffBum();
}
Mehmet Ataş
  • 11,081
  • 6
  • 51
  • 78
2

You can do that with is, but since you are going to want to call something on any dogs you find it would be better to use as:

var dog = a as Dog;
if (dog != null)
{
    dog.sniffButt();
}

However you should be aware that this arrangement (trying to determine the runtime type of a value so that you can cast it to something convenient) is usually frowned upon with good reason. You could easily overdo it and end up checking for dogs, cats, parrots, fish, turtles... I 'm sure you can visualize the resulting mess.

If your needs point towards that scenario, a much better solution is to use the Visitor design pattern.

Jon
  • 428,835
  • 81
  • 738
  • 806
2

Casting checks will not work if the Animal instance has never been a Dog instance.

You may want to look at the Decorator Pattern, which will allow you to add Dog methods to an Animal instance. Essentially, Dog and Animal both have the IAnimal interface. The Dog class takes an Animal instance in the constructor and keeps an internal reference. The Dog's IAnimal implementation simply defers to the Animal instance it references (which allows the Dog to be cast to IAnimal and behave like the wrapped Animal for polymorphism). The Dog also has additional methods that are Dog-specific.

Dr Herbie
  • 3,930
  • 1
  • 25
  • 28
1

An Animal can never be a Dog.

Make your Dog constructor, taking an Animal as parameter.

class Dog : Animal
{
   public Dog(Animal a)
   {
      this.Name = a.Name;
      this.Id = a.Id;
   }

   public void sniffBum()
   {
       Console.WriteLine("sniff sniff sniff");
   }
}
BaBu
  • 1,923
  • 2
  • 16
  • 27
0

I doesn't work like this. Casting is an operation that interprets an instance as the given type, it won't change its type. In your case you have to first determine what kind of animal there is in that particular database row, and then instantiate the correct ancestor. Pseudocode:

var row = Fetch from database;
Animal animal;
if (row is a dog) animal = new Dog();
else if (row is a cat) animal = new Cat();
Ondrej Tucny
  • 27,626
  • 6
  • 70
  • 90
0

You can do this:

var dog = a as Dog;
if(dog != null)
{
    dog.DoSomething();
}

it is preffereable to checking if a is Dog if you need to cast it latter. See the following answer: Casting vs using the 'as' keyword in the CLR

Community
  • 1
  • 1
elolos
  • 4,310
  • 2
  • 28
  • 40
0

You can't cast an animal into a dog, it might be a cat! I think what you're trying to achieve is to create an object of type Dog, from another object of type Animal that's been fetched from db.

One way is to accept an object of type Animal in Dog's overloaded constructor:

class Dog:Animal
{
    public Dog(Animal animal)
    {
        this.Id = animal.Id;
       this.Name = animal.Name;
    }
...
}

This way, you can simply use the following:

if ( some logic to determine that this animal is a dog )
{
    Dog d = new Dog(a);
    d.sniffBum();
}
Kamyar
  • 18,639
  • 9
  • 97
  • 171
0

I would create some static methods on a the Dog object or some kind of DogFactory where you can pas your Animal as a parameter and have it create your Dog, or return null.

In that method you can do checks on your animals characteristics to see if you want it to be a dog (4 legs, bits, whatever)

Otherwise it would be hard to go from an object created as Animal to a concrete Dog object

JMan
  • 2,611
  • 3
  • 30
  • 51
0

Kamyar is right there is no way to do this because like you self told us

i will always have an Animal object coming out of my database like that

so you need to save the type also in your database

after that you should change your Animal to

public class Animal
{
    public long Id { get; set; }
    public string Name { get; set; }
    public string AnimalType { get; private set; }

    public Animal() { }
    public Animal(string type)
    {
        AnimalType = type;
    }

    // to denie self repeading if all animales have the same Properties
    protected void set(Animal a)
    {
        Id = a.Id;
        Name = a.Name;
        AnimalType = a.AnimalType;
    }
}

.

Dog doesnt have any more parameters than Animal has, only new methods

so you can modifie your Dogto

public class Dog : Animal
{
    public Dog(Animal a) 
    {
        base.set(a);
    }

    public void sniffBum()
    {
        Console.WriteLine("sniff sniff sniff");
    }
}

.

i could just create a new Dog object, and pass the values accross, (...), but this just seems messy

i doesn't think there is a way around and it doesn't look that messy

and here the how to use example

        Animal a = new Animal("Dog");
        if (a.AnimalType =="Dog")
        {
            Dog d = new Dog( a);
            d.sniffBum();
        }
WiiMaxx
  • 5,322
  • 8
  • 51
  • 89