2

I saw often people use this code like

interface IAnimal 
{
    void die();
}

class Cat : IAnimal 
{
    void die() { ... }
    void meow() { ... }
}

IAnimal anAnimal = new Cat();
Cat aCat= new Cat();

C# knows for sure anAnimal.die() works, because die() is defined in IAnimal. But it won't let you do anAnimal.meow() even though it's a Cat, whereas aCat can invoke both methods.

Why and when we should write this kind of code:

IAnimal anAnimal = new Cat();

What is the advantage?

6

Because although the compiler could deduce that the meow() call would succeed in this case, it can't do so in every conceivable program, and it's much better to have a simple, easy-to-remember policy of "no type inference" than "I'm going to try some type inference for ya, but I'm warnin' you, I'm not gonna find all the demonstrably legal calls you might expect, so no guarantees."

Therefore, if you're going to call meow() anyway, there is no point whatsoever in declaring something as Animal. Just go ahead and admit that it's a Cat. Interfaces are a useful construct, but they can earn their pay only if you're willing to let them do their abstraction thing, and forget about the exact species.

In general, it rarely makes any sense to declare something as an abstract supertype when you then immediately assign it to a constructor call, i.e. a concrete type. But imagine you had a DogFactory, a CatFactory and a BirdFactory, all of which implement a common PetFactory interface. The PetFactory would contain a method Animal getPet(), and each concrete factory would do something like return new Cat(). The concrete type is needed to actually construct an object; the interface is needed so that different providers can all satisfy the same interface, which simplifies weaving together the application at a higher level.

3
IAnimal anAnimal = new Cat();

You're right. This is doesn't really have a use case, since it has no direct advantage. Since you're hardcoding the object's type (Cat), there is nothing gained from downcasting the type of the variable that references the object.

However, your argument does not hold true when Cat is not hardcoded:

IAnimal anAnimal = myAnimalFinder.FindByName("Fido");

You don't know what animal you're going to get back.

Assuming your software is sold to vets, the result (based on the same name) may differ from vet to vet. Vet A has treated a dog named Fido, vet B has treated a cat named Fido.

This is the real use case, one that actually makes sense in context. The simplified version you were initially referring to is most commonly found in examples, not live code.

But it won't let you do anAnimal.meow() even though it's a Cat

Looking at the real use case, it becomes clear why you can't call meow(). You have no way to guarantee that you're actually going to get a Cat back, so there's no way to know if the returned animal can meow or not.

  • When would you prefer an interface type declaration over var? – Brian White Feb 12 '19 at 1:16
  • @BrianWhite: The main use case of var is that it absolves developers of needing to know the exact type (e.g. ComplicatedResultClass result = GetThatThing();), and to reduce repetition that is already trivially readable (e.g. Student student = new Student();). Using var does not carry a technical benefit at runtime. Following that, you would "prefer" an interface type when you want do be very clear about the type that is being used. But that applies to any type, not just interfaces in general. My general advice is to use var as much as you reasonably can, as it improves readability. – Flater Feb 12 '19 at 5:36
  • Yeah it seems opinion based. I prefer var in the GetThatThing example, over IThatThing. Not sure of a good reason though. – Brian White Feb 12 '19 at 19:56
  • 1
    @BrianWhite: A good example is LINQ, where OrderBy returns a IOrderedEnumerable. Developers generally don't care that this is different from the usual IEnumerable they deal with, and it doesn't make sense to force developers to explicitly mention the different type as the code is perfectly (if not more) readable without it. – Flater Feb 13 '19 at 6:59
1

If you wider the context a little bit, you can find a pretty good use-case for this, like dependency injection. Imagine having a class that depends on another one and calls its method. You want to implement it as a loose coupling code with a minimum dependency between those two classes, so you can replace the dependent class with some other, without breaking the functionality of the class you are calling that second class from.

If you use e.g. constructor injection and assign class passed in a constructor's parameter into a private variable based on your interface type, you can call its methods anywhere in that class and be sure that any class passed in implements that method, as they have to, since they must implement your interface. Should you be calling some methods from the class variable instead of the interface variable, you could not ensure that every single class you can pass in implements that method, as interface says what must some class implement, but does not forbid it from implementing anything else on top of that.

A typical example is DI via constructor injection and interface e.g. in the HomeController in some ASP.NET Core MVC app:

public class HomeController : Controller
    {

//Private variable of the interface type into which you assign a class injected in the constructor        
private readonly IGreetingService _greetingService;

//A constructor accepting any class that implements your interface
public HomeController(IGreetingService greetingService)
        {
            _greetingService = greetingService;
        }

 public string Hello(string id)
        {
            //You call the Greet method via the interface as you can be SURE 
            //that it has this method implemented from the class you have passed in
            return _greetingService.Greet(id);
        }
0

Interfaces generally define behaviours and classes that implement those interfaces are guaranteed to exhibit those behaviours.

interface IDriveable
{
   drive(); 
}

class BMW : IDriveable
{
   drive(); 
   setAirConditioning( int temperature ); 
}

class ModelT : IDriveable
{
   drive(); 
}

Both cars can be driven.

The shiny, new BMW can also do the air-con thing, but that's not a feature of being driveable.

0

Let’s say today your are using a “cat” object, but tomorrow you might decide that a “dog” object is better.

Code that only uses what’s declared in the interface doesn’t need changing, so you want to avoid using cat-specific code that doesn’t work with a “dog” object. And the easiest way to avoid cat-specific code is to assign the cat object to a variable of the “animal” interface type.

The disadvantage: Neither the cat’s “meow” method nor the dog’s “bark” method can be used. The advantage: The same.

Not the answer you're looking for? Browse other questions tagged or ask your own question.