c# - 编译时限制 : Allow As but not Bs where B:A

标签 c# generics types

在下面的层次结构中,是否有一种方法可以在编译时排除 IBar,同时仍然允许 IFoo?

示例:

//IFoo defines functionality that Snafu needs to use, and so is a type restriction.
public interface IFoo {...}

//IBar defines supplemental required functionality that Snafu does not support.
public interface IBar:IFoo {...}

//Can I generate a compiler error if an IBar is used as the generic type?
public class Snafu<T> where T:IFoo
{
    public void DoSomethingWith(T myFoo)
    {
        //Best thing I can think of with the current hierarchy
        if(myFoo is IBar) throw new ArgumentException("IBars are not supported");
    }
}

我能想到的唯一有效的方法是定义第三个“标志”接口(interface),并将其应用于所有不是 IBar 的 IFoo。定义 IFoo 和 IBar 后:

public interface IAmNotAnIBar:IFoo {}

public class Snafu<T> where T:IAmNotAnIBar {...}

然而,这听起来像是黑客攻击;新接口(interface)没有定义 IFoo 没有的任何新内容,开发人员必须知道不要使用 IFoo(IIRC,您不能通过将 IFoo 设为内部来隐藏 IFoo,同时仍将其他接口(interface)公开为公共(public)接口(interface)),因此他们可以只需实现 IFoo 即可绕过善意或恶意的编译时检查。还有更优雅的吗?

编辑:感谢大家到目前为止的回复。也许一个更具体的例子可以说明我首先问这个问题的原因。

假设 IFoo 定义了映射到数据库的域对象的基本功能。它必须具有读写 ID 属性,也许能够发出和吸收 DTO,等等。系统中有几个区域将这些对象作为 IFoo 进行处理,包括持久性:使用可以处理任何 IFoo 的存储库(上例中的 Snafu 类;DoSomething() 执行一些持久性操作)读取 IFoo 并将其写入持久性存储在强类型 IFoo 上)。

现在,让我们将 IBar 定义为一个域对象,其填充方式与 IFoos 不同。除了 IFoo 功能之外,它们还定义了一些附加的 Initialize() 方法,以确保它们处于一致的状态。它们仍然是域对象 (IFoos),并且在系统的所有区域中仍应被视为域对象,除非您无法将 IBar 传递给 Snafu 实例并期望正确的结果,因为 Snafu 不会也无法正确调用该方法(假设 Initialize() 接受的参数是外部依赖项,而 Snafu 没有且不应给出该参数)。相反,您应该调用一个不同的类,即所有 IBar 的存储库。我的目标是,在编译时,提醒开发人员他们做错了什么,而不是依赖于 Snafu 上对 DoSomething() 的每个可能调用的充分运行时测试(单元、集成、功能、手动等)以确保它从未通过 IBar。

最佳答案

如果您尝试在允许 IFoo 的同时排除 IBar,这告诉我 IBar 不应该真正继承自 >IFoo(他们并不是真正的父子关系)。

请记住,仅仅因为两个接口(interface)共享同名成员,并不意味着一个接口(interface)应该从另一个接口(interface)继承。如果您像这样使用继承,则会为从父级继承的成员赋予新的含义,从而违反了里氏替换原则。就您而言,很明显 IBar 不是 IFoo...否则您不需要限制它们的使用。

我的猜测是有一种方法可以重构你的界面,让事情变得更有意义,但如果没有更多细节,我很难说。

关于c# - 编译时限制 : Allow As but not Bs where B:A,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4368925/

相关文章:

c# - DataContext 的生命周期,LinqToSql

swift - 在 Swift 中通过函数传递泛型类型

c# - 界面中发生了什么?

vba - 数组/集合和每个循环中的用户定义类型

c - "type domain"和 "real type"是什么意思?

c# - Java 枚举类型的 C# 等效项是什么?引用下面的代码

c# - Web API OData v4 $count=true 被忽略

c# - 在使用流后离开流的社会可接受的方式是什么?

iOS - 如何使用泛型在类上遵守 NSItemProviderWriting 和 NSItemProviderReading 协议(protocol)

haskell - 如何测试这种数据类型的半群定律?