The returned interface, but the specific one may have properties not on the interface, can I get them with a cast?

I have the feeling that my use of the interface is wrong. I know that an interface is a contract that a particular class must adhere to.

So, I will explain the problem I'm trying to solve, and maybe someone can point me in the right direction.

I am creating an application that returns a page for any request, I have three types of pages, Cms, Product and Category.

All three must implement the following interface:

public interface IPage { PageType PageType { get; set; } PageContent Content { get; set; } Meta Meta { get; set; } } 

These properties are requested regardless of page type.

A page can have additional properties depending on their type, for example, a category page can be like this:

 public class CategoryPage : IPage { public PageType PageType { get; set; } public PageContent Content { get; set; } public Meta Meta { get; set; } public List<Product> Products { get; set; } } 

At the moment, I have a page service that will return a page for the requested URL.

Depending on the type of page it knows, what type of page should be returned.

The problem is that the pageService returns an IPage so that it can return any of the page types.

This is a problem, because not all of my concretes just implement the interface, in the case of a category page it also has a list, which, as expected, I can’t access unless I apply a specific type.

But is there a way to return the general type of the page and find out what the recipient is?

I am sure that as I do this, the moment is not the best way, and I would like to receive some direction and advice on how I can solve this small problem.

thanks

Update

I agreed to the cast.

I am sure that there should be a better way to deal with a situation where several classes use some basic properties, but also implement their own. when you get one of these classes from a service, you need to know what you have so that you can work with the appropriate properties.

Or maybe what I'm trying to do here is simply wrong, and I need to take a different approach. I think I will insist on what I have, but I continue to think about it.

Update 2

I changed the way I do this, so I don’t need to apply, I have a PageType enumeration that I use to determine the type of page that it works with.

Combined with an Ipage that inherits everything you need, it seems to be a pretty good solution and eliminates the need for casting.

+4
source share
4 answers

You can always check if an object that has a link is of a specific type using the keyword ;

 if(obj is Class1) { 

However, if your design requires you to know specific types, chances are something is wrong with the design itself. If there are differences in behavior between classes, implement the differences within the classes, instead of using them to implement outside of them.

+2
source

If your receiver needs to know a specific type, then you are not using the interfaces correctly.

If you return a page, there really is no reason to find out which page. I would add a Render method to the IPage interface IPage that the entire recipient should make a call to Render() and the page will process the rest.

+1
source

Here are two ways to verify that your interface returned from the service is your specific type.

  IPage page; if (page is CategoryPage) { // use type here } CategoryPage categoryPage = page as CategoryPage; if (categoryPage != null) { // use type here } 
0
source

Ideally, you will almost never need to use machine tricks, especially given the availability of generics. From a pragmatic point of view, however, sometimes it’s better to use tricks like going over huge lengths to avoid them.

In a sense, it is not elegant to have a collection of objects that have different abilities (or a factory method that will return different abilities) in cases where it may be necessary to use the abilities that exist in some objects, but not others. Of course, you can say something like

  IInterfaceThatMayOrMayNotBePresent foo = bar as IInterfaceThatMayOrmayNotBePresent;
   if (foo! = null)
     foo.MethodOfThatInterface ();

but that is a bit of code smell. It is often useful to determine why you need to use methods that are not found in all instances in the list, and determine if a better class can be useful.

For example, suppose some types of objects want to be notified if "Wowzo" occurs; other types don't care. In addition, it is expected that they will have lists containing objects of both types, and they will need to be notified about all the elements that interest you. You can use the above type checking template to notify only those items that need it, but there may be a more efficient approach: you can define two interfaces: IAcceptWowzoNotifications and IActOnWowzoNotifications , the latter inheriting the former. Classes that implement the first, but not the second, expected to implement Wowzo notifications with empty methods. If each item in the list implements IAcceptWowzoNotifications, regardless of whether it does anything with such a notification, it will be faster to just notify everyone in the list than to check which items need to be notified.

Please note that this approach is not entirely without cost. First of all, since interfaces do not provide default implementations, each type that implements IAcceptWowzoNotifications will need to define stub methods. In addition, if the only reason the item will be placed on the list is to send Wowzo notifications, and if the notification on each of the lists will be more frequent than adding items to the list, it would be better to check whether the elements implement IActOnWowzoNotifications before adding them to the list, than blindly add items to the list, which may or may not be there.

Interface inheritance hierarchies are very powerful and in many cases underutilized. The fact that the implementation of the interface does not need to worry about which members came from which ancestor interfaces simplifies the separation of interfaces with a much lesser headache than when splitting classes.

0
source

Source: https://habr.com/ru/post/1393530/


All Articles