返回接口但混凝土可能有不在接口上的属性,我可以通过强制转换获得它们吗
本文关键字:接口 转换 可以通过 可能有 混凝土 属性 返回 | 更新日期: 2023-09-27 18:21:37
我觉得我对接口的使用是不正确的。我知道接口是具体类必须遵守的契约
所以我会解释我试图解决的问题,也许有人能给我指明正确的方向。
我正在构建一个应用程序,可以为任何请求返回页面,我有三种页面类型,Cms、Product和Category。
三者都必须实现以下接口:
public interface IPage
{
PageType PageType { get; set; }
PageContent Content { get; set; }
Meta Meta { get; set; }
}
无论页面类型如何,都需要这些属性。
一个页面可能有额外的属性,这取决于它们的类型,例如一个类别页面可能是这样的:
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; }
}
目前,我有一个页面服务,它将为请求的url返回一个页面。
基于PageType,它知道返回什么类型的页面。
问题是pageService返回一个IPage,这样它就可以返回任何页面类型。
这是一个问题,因为并不是我所有的混凝土都只实现了接口,在类别页面的情况下,它也有一个列表,正如你所料,除非我转换为混凝土类型,否则我无法访问它。
但是,有没有一种方法可以返回一个通用的页面类型,并让接收者知道它是什么具体的?
我确信我现在的做法不是最好的方式,我希望得到一些关于如何解决这个小问题的指导和建议。
感谢
更新
我已经决定选演员了。
我相信一定有更好的方法来处理这样一种情况,即几个类使用一些基本属性,但也实现它们自己的属性。当您从服务中获得其中一个类时,您需要知道您得到了什么,以便可以使用相关的属性。。
或者,也许我在这里试图做的是完全错误的,我需要采取另一种方法。我想我会继续努力,但要继续思考
更新2
我已经改变了这样做的方式,所以我不需要强制转换,我有一个PageType枚举,用于识别正在使用的页面类型。
再加上Ipage继承了所需的一切,这似乎是一个足够好的解决方案,并消除了对演员阵容的需求。
您可以始终使用is关键字检查您引用的对象是否属于特定类型;
if(obj is Class1) {
也就是说,如果你的设计要求你知道具体的类型,那么很可能是设计本身出了问题。如果类之间的行为存在差异,请在类内部实现差异,而不必强制转换它们以在类外部实现。
如果您的接收器必须知道具体类型,那么您没有正确使用接口。
如果你要返回一个页面,实际上没有任何理由知道它是什么类型的页面。我会在IPage
接口中添加一个Render
方法,这样接收器所要做的就是调用Render()
,页面将处理其余的内容。
这里有两种方法可以检查从服务返回的接口是否是你的具体类型。
IPage page;
if (page is CategoryPage)
{
// use type here
}
CategoryPage categoryPage = page as CategoryPage;
if (categoryPage != null)
{
// use type here
}
理想情况下,几乎不需要使用类型转换,特别是考虑到泛型的存在。然而,从实用的角度来看,有时使用类型转换比不遗余力地避免它们要好。
从某种意义上说,在可能需要使用某些对象中存在但其他对象中不存在的能力的情况下,拥有一组具有不同能力的对象(或返回不同能力的工厂方法)是不雅的。说这样的话当然是可能的
IInterfaceThatMayOrMayNotBePresent foo=bar as IInterfacethatMayOrmayNotBePresents;if(foo!=null)foo。MethodOfThatInterface();
但这有点代码味。通常最好确定为什么需要使用列表中所有实例中都不存在的方法,并确定更好的类设计是否有帮助。
例如,假设某些类型的对象希望在发生"Wowzo"时得到通知;其他类型的人不在乎。此外,人们希望有包含这两种类型的对象的列表,并且需要通知所有关心的项目。可以使用上面的类型检查模式只通知那些需要它的项,但可能有一种更有效的方法:可以定义两个接口:IAcceptWowzoNotifications
和IActOnWowzoNotifications
,后者继承第一个。实现第一个但不实现第二个的类将使用空方法实现Wowzo通知。如果列表中的每个项目都实现了IAcceptWowzoNotifications,无论它是否使用这种通知做了任何事情,那么简单地通知列表中的所有人将比检查哪些项目需要通知更快。
请注意,这种方法并非完全没有成本。首先,因为没有提供提供默认方法实现的接口,所以实现IAcceptWowzoNotifications
的每个类型都需要定义存根方法。此外,如果一个项目被放在列表中的唯一原因是向它发送Wowzo通知,并且如果列表中每个人的通知比向列表中添加项目更频繁,那么在将项目添加到列表之前,最好检查项目是否实现了IActOnWowzoNotifications
,而不是盲目地将可能需要或不需要的项目添加到该列表中。
接口继承层次结构非常强大,而且在许多情况下未得到充分利用。事实上,接口实现不必担心哪些成员来自哪些祖先接口,这使得拆分接口变得容易,而且比拆分类时头痛得多。