views:

408

answers:

7

C#

Hi all,

I pass an object to a method.

I want to cast that object to its specific class so I can perform its own specific methods? How can I do that?

Move( new Cat() );
Move( new Pigeon() );

public void Move(object objectToMove)
{
    if(objectToMove== Cat)
    {
        Cat catObject = objectToMove as Cat;
        catObject.Walk();
    }
    else if(objectToMove== Pigeon)
    {
        Rat pigeonObject = objectToMove as Pigeon;
        pigeonObject.Fly();
    }
}
+3  A: 

You can use the "is" operator to check if an object is an implementation of a certain class.

if (objectToMove is Cat)
Yannick Compernol
thanks very much :) 17 secs! just pipped to the post
divinci
+7  A: 

Well, you can use the is keyword like this:

if(objectToMove is Cat)
{
    ...
}
else if(objectToMove is Pigeon)
{
    ...
}
Yogesh
thanks for the quick answer
divinci
Don't use `is` and `as` together as it is redundant casting (for more info please read my article about this: http://togaroga.com/blog/2009/09/two-casts-are-not-better-than-one/). A more scalable solution for the OP's particular problem is proposed by Groo here: http://stackoverflow.com/questions/1666496/c-casting-an-object-parameter-into-that-objects-type/1666564#1666564.
Andrew Hare
+1  A: 

Just a bit of change in your and it's good to go.

Move( new Cat() );
Move( new Pigeon() );

public void Move(object objectToMove)
{
    if(objectToMove is Cat)
    {
        Cat catObject = objectToMove as Cat;
        catObject.Walk();
    }
    else if(objectToMove is Pigeon)
    {
        Rat pigeonObject = objectToMove as Pigeon;
        pigeonObject.Fly();
    }
}
this. __curious_geek
+4  A: 

One small point... It's more correct to not use as and is together as the second type check implied is redundant. Either use as in the following manner:

Cat catObject = objectToMove as Cat;
if(catObject!=null)
    catObject.Walk();
else 
{
    Pigeon pigeonObject = objectToMove as Pigeon;        
    if(pigeonObject!=null)
        pigeonObject.Fly();    
}

Or do a direct cast as you are sure it will succeed; this is both more efficient and more clear:-

if(objectToMove is Cat)    
{        
     Cat catObject = (Cat)objectToMove;        
     catObject.Walk();    
}    
else if(objectToMove is Pigeon)    
{        
     Pigeon pigeonObject = (Pigeon)objectToMove;        
     pigeonObject.Fly();    
}

Using a direct cast you get an exception if it fails, rather than a null. People reading the code will know without context "We're not just trying to see if it can be treated as something, we're sure that we've ascertained that it should be possible.

Ruben Bartelink
is uses two typechecks. as uses 1. I af prette sure as the more efficient one. All through the .NET framework as is used.
Esben Skov Pedersen
@EsbenP: Not sure what your point is, but mine is 1. Efficiency:- `y=x as Y; if(y!=null){y.Something();}` is more efficient than if(x is Y) { y=x as Y; y.Something();}` - the `as` is checking whether it really `is` Y *again*. 2. Clarity: if you've already established that x `is` Y, using `as` instead of a direct cast, i.e. `(Y)` is less clear as to what you're doing. Thus, instead of saying `if(x is Y){Y y=x as Y;}` one should instead say `if(x is Y){Y y=(Y)x;}` This makes it clear that you're not trying to do anything conditional.
Ruben Bartelink
On the other hand, I know many people mis-use `as`. I also know that in concrete terms, the perf, IL size or JITted code size difference between a conditional cast and a non-conditional [Direct] cast is pretty moot. But doing a type check followed by a conditional cast of the same type *is* redundant.
Ruben Bartelink
Ruben Bartelink
Related question: http://stackoverflow.com/questions/2139798/why-is-the-c-as-operator-so-popular/2140136#2140136
Ruben Bartelink
+22  A: 

The right way to do this would be:

public interface ICanMove
{
   void Move();
}

implemented by both Cat and Pigeon:

public class Cat : ICanMove
{
   public void Move() { /* do something */ }
}

public class Pigeon : ICanMove
{
   public void Move() { /* do something */ }
}

And then call it like this:

public void Move(ICanMove objectThatMoves)
{
   objectThatMoves.Move();
}

You gain several things:

  1. You can only call the Move(ICanMove objectThatMoves) for an object that implements the interface. If you try to pass a different object, your program will not compile.
  2. You lose the conditional statement. If you decide to add a Dog which implements ICanMove to your program, the Move method will work great without any modifications. In your version you will have to change the method.

Imagine how much work you would have if you had is statements all over your program?

Groo
+1 This is the way to do it.
Andrew Hare
A: 

What I would do is this:

interface IAnimal
{
 void Move();
}

An interface

Then my cat and my bird:

class Cat : IAnimal
{
 public void Move()
 {
  //a cat moves by walking
  this.Walk();
 }

 public void Walk()
 {
  //do logic
 }
}

class Bird : IAnimal
{
 public void Move()
 {
  this.Fly();
 }

 public void Fly()
 {
  //do fly logic
 }
}

So when you're done you get this:

public void Move(IAnimal animal) { animal.Move(); }

And should you want to check the type of your animal you can do this:

public void PrintType(IAnimal animal)
{   
    Console.WriteLine(typeof(animal));
    //or
    Console.WriteLine(animal.GetType());
}
Snake
+4  A: 

Another solution instead of using an interface would be to have a base class and to override the Move() method in each derived class.

    abstract class Animal
    {
        public abstract void Move();
    }

    public class Cat : Animal
    {
        public override void Move()
        {
            //Cat specific behavior
        }
    }

    public class Bird : Animal
    {
        public override void Move()
        {
            //Bird specific behavior
        }
    }

I think using a base class is better if you have properties or methods that are common to all your "animals". This way you don't have to duplicate code in each class that implements the "IAnimal" interface described above.

Of course if there are no common elements interface works fine.

FrenchData