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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With