Dietpixel
Dietpixel

Reputation: 10123

Casting in C# with interfaces to be able to use all object functionality

I'm having a bit of an issue casting my objects in C# to be able to use the additional object methods besides the ones declared in the interface. Below is a simple example of what I am speaking about.

public interface IShape
{
    void Print();
}

public class Square : IShape
{
    #region IShape Members

    public void Print()
    {
        HttpContext.Current.Response.Write("Square Print Called"); 
    }   

    #endregion

    public void PrintMore()
    {
        HttpContext.Current.Response.Write("Square Print More Called"); 
    }        
}

Why when this code below is called am I not able to access PrintMore()?

IShape s = (Square)shape;
s.PrintMore() // This is not available. only Print() is. 

Any help and explanation would be helpful?

Upvotes: 3

Views: 159

Answers (6)

Chris Klepeis
Chris Klepeis

Reputation: 9983

Because when you try s.PrintMore() "s" is of type IShape, so it only knows about the interface functions. You'd need to do something like

Square s = (Square)shape;  
s.PrintMore();

or

((Square)shape).PrintMore(); // assuming you're positive its a Square type

Think of the interface like a wrapper over your object that only exposes only the functions defined in the interface. They're still there, you just can't access them without a cast to the appropriate object.

Upvotes: 1

Johannes Kommer
Johannes Kommer

Reputation: 6451

The reason you are unable to access the PrintMore method is because you're reassigning the type-casted shape, back to a variable defined as IShape. To be able to use methods on the Square class you need to store it in a variable of type Square for example:

Square s = (Square)shape;
s.PrintMore(); 

or alternatively:

((Square) shape).PrintMore();

Although it might be worth taking a good look at your code, type-casts such as these are usually a good warning sign that perhaps it is not ideal. Perhaps IShape should have the PrintMore method, or perhaps you should only be accepting Square objects at this point? At the very least I'd suggest making sure that the shape is actually of type Square before doing this type cast.

For example:

Square s = shape as Square;

if (s != null)
    s.PrintMore(); 

Upvotes: 1

Matthieu
Matthieu

Reputation: 4620

IShape s = (Square)shape; 
s.PrintMore();

With this code s is still an IShape, not a Square. A variable keeps the type you have defined at his declaration, whatever you try to fill in it.

To work the code should be :

Square s = (Square)shape; 
s.PrintMore();

Upvotes: 2

Jon Skeet
Jon Skeet

Reputation: 1500225

Your s variable is still of type IShape. Just because you happen to have used a cast when assigning to it doesn't change the type as far as the compiler's concerned. You'd need:

Square s = (Square) shape;
s.PrintMore();

Of course, this will only work if shape really is a Square (assuming there aren't custom conversions going on).

I would advise you to think carefully before going down this route though. Usually a cast like this indicates that you're breaking abstraction somewhat - if you only know about shape as an IShape, you should (usually) be able to do what you need just with the members of IShape. If that's not the case, you can:

  • Make IShape more powerful (give it more members)
  • Change your code to accept a Square instead of an IShape
  • Cast if absolutely necessary

Upvotes: 5

James Michael Hare
James Michael Hare

Reputation: 38397

The problem is you are trying to access PrintMore() off of an IShape reference, IShape references only see the Print() method they declare.

So the cast you have (Square) shape is doing nothing because it is immediately storing it into an IShape reference. You need the reference itself to be Square by either casting and storing it in a Square reference, or by casting before the invoke:

Square s = (Square) shape;
s.PrintMore();

Or

IShape s = shape;
((Square)s).PrintMore();

Or, if you aren't sure if it's a Square or not, use an as cast:

Square s = shape as Square;

// will cast if it is a Square, otherwise, returns null 
// this doesn't work for value types (int, struct, etc) 
if (s != null)
{
    s.PrintMore();
}

Upvotes: 4

Chris
Chris

Reputation: 27599

In the line IShape s = (Square)shape; you are telling the compiler that s is an IShape so only methods on IShape are available.

If you user:

Square s = (Square)shape;
s.PrintMore()

Then that should do what you want.

The key point here is that when you declare a variable you tell the compiler what it is and it doesn't then matter what object you put into that.

Upvotes: 3

Related Questions