Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to cast from a concrete class to an interface type?

Tags:

c#

I am building a multi layered application.

When i pass an object from my presentation layer to my business layer, i want to cast it to an interface type, because the business layer does not know of the concrete class from the presentation layer.

    public ActionResult SubmitSurvey(SurveyAnswer answers)
    {

        ISurveyAnswer answer = (ISurveyAnswer)answers;

        bc.SaveSurvey(answer);

        return null;
    }

The class SurveyAnswer implements the interface ISurveyAnswer

When i check the type in the business layer:

 public void SaveSurvey(ISurveyAnswer answer)
        {
            String type = answer.GetType().Name;
        }

the GetType().Name method returns SurveyAnswer which is the concrete class from the presentation layer. Is it supposed to do that?

like image 578
Kenci Avatar asked Dec 06 '22 14:12

Kenci


1 Answers

Casting does not change the type of the object. The object always remains the same as when it was created. Casting simply changes the interface through which you are accessing the object. It changes your "view" of the object, if you will. It's not a problem, though. What you are doing is correct. All the UI layer cares about is the ISurveyAnswer interface, so as long as the object's concrete type implements that interface, then all is well and will work as you expect. The beauty of doing so it that now the UI layer may be given any kind of object (including mock objects) and it won't matter, as long as the object implements that same interface, the UI will work and won't care. GetType will let you inspect the object to see what the actual type of the object is, but in most cases, it shouldn't matter to the UI layer. As long as the provided object implements that interface and works properly, so will the UI.

When any class or method asks that an object of some type is passed to it, it should ideally always ask for the most narrow implementation or base type as is possible. So for instance, if you have a method that takes a list of items, it could look something like this:

void printList(List<Dog> dogs)
{
    foreach(Dog dog in dogs)
        printDog(dog);
}

However, technically, the method doesn't really need a List<> object, because all it's doing is enumerating through the items in the list. It's not using any of the members of the List<> type, itself, it's just using the members of the IEnumerable<> interface, which is implemented by the List<> type. Therefore, it would be better in this case to code the method like this:

void printList(IEnumerable<Dog> dogs)
{
    foreach(Dog dog in dogs)
        printDog(dog);
}

Now, if inside the method, it not only needs to enumerate through the list, but also needs the total count of items in the list, then IEnumerable is not enough. But still, it wouldn't need the full List<> type, it just needs the ICollection<> type (which is also implemented by List<>), like this:

void printList(ICollection<Dog> dogs)
{
    printTotal(dogs.Count);
    foreach(Dog dog in dogs)
        printDog(dog);
}

But if the method neededs to get the index of each item, ICollection<> isn't enough--the method would need an IList<> type. For instance, this example shows how it might print the list of dogs and highlight every other one in the list:

void printList(IList<Dog> dogs)
{
    printTotal(dogs.Count);
    for(Dog dog in dogs)
        if (dogs.IndexOf(dog) % 2 == 0)
            printDog(dog);
        else
            printHighlightedDog(dog);
}

You'll notice that in none of these examples did I have to cast the dogs argument into a different type. I typed the argument appropriately for what I needed, so I just use it through that type's interface. In all of these examples, a List<Dog> object can be passed into the printList method without casting (because List<> implements all of those interfaces so it can be cast implicitly):

List<Dog> dogs = new List<Dog>();
dogs.Add(new Dog());
printList(dogs);

Keep in mind, this is a very simplistic example to illustrate a point. In real world scenarios, you very often may just ask for List<> or IList<> even if you don't technically need everything they offer, for various reasons. You may know that the method may very likely will need IList<> functionality in the future, even though it only needs the IEnumerable<> functionality today. But, the principle is a very good one to keep in mind as you decide on the types for arguments to your methods.

You almost never need to know the actual type of an object that is passed into a method. All you really need to know is that it implements a particular interface so that you can access its functionality through that particular interface.

like image 198
Steven Doggart Avatar answered Jan 31 '23 10:01

Steven Doggart