【问题标题】:Non-strict multiple interface type parameter constraints?非严格的多接口类型参数约束?
【发布时间】:2009-12-12 00:02:02
【问题描述】:

如果这是一个骗局,请原谅,但我似乎无法获得正确的关键字组合来过滤掉各种类型约束和泛型问题(因为有很多)。

我有两个接口——我们称它们为 IOnlineIOffline

它们密切相关,因为它们描述了几乎相同的合约,但它们之间的主要区别之一是使用具体实现的上下文。这不完全是我的情况,但它很好地说明了问题。

然后我有一些方法可以针对这些接口的具体实现者工作。有时这些方法只想处理一种类型而不是另一种。

足够简单:

public void DoStuff<T>(string foo) where T : IOnline {}

Kicker 正在实现可以在任何一种类型上运行的方法的代码。我认为这是正确的,但是在阅读编译错误时,我期望约束将被解释为“如果它们实现 IOnline 或 IOffline,则允许在此处一般使用任何类型 T”,实际上被解释为“允许任何类型如果他们实现 BOTH,则此处一般使用 T”。

public void DoStuff<T>(string foo) where T : IOnline, IOffline {}

尝试实现两个具有相同名称但不同约束的独立方法会失败,因为存在明显的歧义问题——我们没有重载,因为参数列表是相同的(因为所需的行为是相同的)。

可以为两种不同的方法使用两个不同的名称,每种方法都有适当的约束,但这看起来很笨拙,并且使下游的其他事情变得很麻烦......可行,但不是理想。

我觉得这里一定有一些我想念的东西......我在普通的土地上感觉非常舒服,但这是我第一次必须完成我所追求的事情,我觉得我只是旋转我的轮子atm。

【问题讨论】:

    标签: c# generics type-constraints


    【解决方案1】:

    在第二个示例中提供多个约束确实是附加的。 MSDN page on generic constraints 对此有所了解。

    你能否让你的两个接口继承自一个基接口,并将方法约束到基类型?

    【讨论】:

    • 老实说,我最近才知道 C# 支持接口继承。在十年的开发工作中,这种需求从未出现过。必须试一试,看看它是否最终能把我带到我需要的地方。
    【解决方案2】:

    这可能不是您问题的答案,但我自发地感觉到您可能想要重构您的界面。根据您的问题:

    它们密切相关,因为它们 描述几乎相同的合同, 但两者之间的主要区别之一 它们是其中的上下文 将使用具体的实现。

    我对接口的看法是它们是合约。他们定义了事物应该如何看起来,而不是它应该如何表现;这就是执行的任务。现在,我没有关于您的应用程序或问题域的信息,但我可能会尝试花一些时间来识别这些接口的相同部分并将它们移动到单个接口中,并且只将差异保留为单独的接口。这样您或许可以更轻松地解决这些问题。

    【讨论】:

    • 它归结为我想的意图 - 我已经看到接口用作您所描述的合同,但我经常看到这样的论点,即接口虽然是合同,但最终描述了如何对象的行为(作为受所述合同约束的副作用)。尽管您的观点是,我们可能需要重构我们如何区分两种上下文,但这可能是合理的。不过,我们想要接口还有更细微的原因……哎呀!
    【解决方案3】:

    我认为 .NET 中执行此操作的标准方法是拥有一个包含您的 IOnline 和 IOffline 函数的接口,然后是一些属性,说明哪些函数实际上是在特定类中实现的。您可以在 .NET 的各个地方看到这种模式,例如可能实现也可能不实现的 Seek() 方法以及可以测试的 CanSeek 属性。

    这可能不是最简洁的 OO 设计,但它确实有效。

    【讨论】:

    • 另一种方法是定义单独的 IOnline 和 IOffline 接口,以及继承两者的 IOnlineAndOffline 接口。如果实现了 IOnline 和 IOffline 的类也实现了 IOnlineAndOffline,那么这种方法效果很好。如果可能会使用多种接口组合,那么这种方法会有些混乱。还有另一种方法可以扩展到任意数量的接口而不会出现组合爆炸,但它有点棘手。
    • @supercat:我忘了我已经发布了这个......哇,一年后零票!嗯,我想我会删除它而不是修复它,但无论如何感谢您的评论!
    • 我确实有兴趣尝试明智地处理非分层接口。看看stackoverflow.com/questions/4373259/…,它可能在我的解决方法上花费了太多时间,而在问题上还不够,如果有任何意义,请告诉我。
    【解决方案4】:

    丢失了一些编译时检查,但我看不到任何解决方法...您必须选择您更愿意使用的,(我假设您的偏好是在线的):

    public void DoStuff<T>(string foo)
    {
        Type type = typeof(T);
        if(type.GetInterfaces().Contains(typeof(IOnline)))
             doStuffOnline<T>(foo);
        else if(type.GetInterfaces().Contains(typeof(IOffline)))
             doStuffOffline<T>(foo);
        else
             throw new Exception("T must implement either IOnline or IOffline");
    }
    
    private void doStuffOnline<T>(string foo){ // can assume T : IOnline }
    private void doStuffOffline<T>(string foo){ // can assume T : IOffline }
    

    【讨论】:

    • 不得不说我同意其他人的观点...更好的 OOP 方法来做到这一点,例如单个基础接口...
    猜你喜欢
    • 1970-01-01
    • 2022-06-11
    • 2020-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-20
    相关资源
    最近更新 更多