【问题标题】:Returning interface but concrete may have properties not on the interface, can I get them with a cast?返回接口但具体的属性可能不在接口上,我可以通过强制转换获得它们吗?
【发布时间】:2012-02-10 16:48:22
【问题描述】:

我感觉我对界面的使用不正确。我知道接口是具体类必须遵守的契约。

所以我将解释我要解决的问题,也许有人可以指出我正确的方向。

我正在构建一个为任何请求返回页面的应用程序,我有三种页面类型,Cms、产品和类别。

这三个都必须实现以下接口:

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 相结合似乎是一个很好的解决方案,并且无需演员表。

【问题讨论】:

    标签: c# asp.net interface concreteclass


    【解决方案1】:

    您始终可以使用is keyword 来检查您引用的对象是否属于特定类型;

    if(obj is Class1) {
    

    也就是说,如果您的设计要求您了解具体类型,那么设计本身很可能存在问题。如果类之间的行为存在差异,请在类内部实现这些差异,而不必强制它们在它们之外实现。

    【讨论】:

    • 我会强制转换以获取不属于接口的属性的值。我曾考虑使用 if(page.GetType == typeof(CategoryPage)) - 但我真的不想,我同意设计是错误的,根据问题中的信息,你能给我一些指导以更好设计?
    【解决方案2】:

    如果您的接收者必须知道具体类型,那么您没有正确使用接口。

    如果您要返回一个页面,实际上没有任何理由知道它是什么类型的页面。我会在IPage 接口中添加一个Render 方法,这样接收者所要做的就是调用Render(),然后页面将处理其余的事情。

    【讨论】:

    • "我感觉我对界面的使用不正确。" - 我的第一句话同意你的:) 因此这个问题。我喜欢 Render() 方法的想法,会考虑一下。
    【解决方案3】:

    这里有两种方法可以检查你从服务返回的接口是否是你的具体类型。

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

    【讨论】:

    • 谢谢,问题是我不想这样做,我使用的设计似乎是错误的,但我不确定如何更好地实现它。也许我需要改写我的问题。
    • 是的,如果您可以控制所有课程,贾斯汀的答案会更好。
    【解决方案4】:

    理想情况下,几乎不需要使用类型转换,尤其是考虑到泛型的存在。然而,从实用的角度来看,有时使用类型转换比竭尽全力避免它们更好。

    从某种意义上说,在可能需要使用某些对象中存在但其他对象不存在的能力的情况下,拥有具有不同能力的对象(或将返回不同能力的工厂方法)的集合是不优雅的。当然可以这样说

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

    但这有点代码味道。通常最好确定为什么需要使用列表中所有实例中未出现的方法,并确定更好的类设计是否有帮助。

    例如,假设某些类型的对象想要在“Wowzo”发生时得到通知;其他类型无所谓。此外,人们希望有包含两种类型对象的列表,并且需要通知所有关心的项目。可以使用上述类型检查模式只通知那些需要它的项目,但可能有更有效的方法:可以定义两个接口:IAcceptWowzoNotificationsIActOnWowzoNotifications,后者继承第一个。实现第一个但不实现第二个的类预计会使用空方法实现 Wowzo 通知。如果列表中的每个项目都实现了 IAcceptWowzoNotifications,那么无论它是否对此类通知执行任何操作,简单地通知列表中的每个人都会比检查哪些项目需要通知更快。

    请注意,这种方法并非完全没有成本。首先,因为没有提供接口来提供默认方法实现,所以实现IAcceptWowzoNotifications 的每个类型都需要定义存根方法。此外,如果将一个项目放在列表中的唯一原因是向它发送 Wowzo 通知,并且如果通知列表中的每个人比将项目添加到列表中更频繁,那么最好检查是否items 在将它们添加到列表之前实现IActOnWowzoNotifications,而不是盲目地将可能需要或可能不需要的项目添加到列表中。

    接口继承层次结构非常强大,并且在许多情况下未被充分利用。接口实现不必担心哪些成员来自哪个祖先接口,这一事实使得拆分接口变得很容易,而且比拆分类所带来的麻烦要少得多。

    【讨论】:

      猜你喜欢
      • 2011-04-17
      • 1970-01-01
      • 2012-06-30
      • 2020-10-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-01
      • 2020-11-07
      • 2023-03-16
      相关资源
      最近更新 更多