8

我已经在考虑这个(元)问题几天了:
是否可以定义有效的 C# 接口,但不能以任何方式实现?

这个问题的可能变化:是否可以在C# 2.0, 3.0, 4.0, 5.0中定义这样的接口?是否可以定义这样的接口,在实现时甚至不会编译,或者会编译但抛出运行时异常?

编辑:我知道根据定义,这样的界面将毫无用处,但对于讲座或测试编程工作的申请人来说,他们对 C# 的了解程度是一个很好的答案。

4

4 回答 4

17

是否可以定义无法实现的有效 C# 接口?

这个琐事问题不适合 StackOverflow,但到底是什么,很容易回答。(错误地,事实证明!继续阅读!)

class C
{
    private C() {}
}
interface IFoo<T> where T : C, new()
{
}

IFoo<T>无法为 any 实现,T因为没有类型参数可以替代T. C不起作用,因为C没有公共的无参数构造函数,并且C由于默认构造函数是私有的,所以不能有派生类。(好吧,可能有一个可访问的Cinside派生类C,但在这种情况下没有。)


更新:评论者“mike z”正确地指出

class X<T> : IFoo<T> where T : C, new() {}

实现了接口,当然现在没有办法实例化X<T>

更好的是,用户“GranBurguesa”指出允许声明 C 的派生类,只要它从不调用私有构造函数即可;这只有在它在实例化时崩溃并死掉时才有可能。(好吧,为了挑剔,还允许将递归调用优化为无限循环而不是崩溃。)

这两种迂回的变通方法都提出了一个哲学问题:如果一个接口是由一个没有人可以实例化的类实现的,那么它真的实现了吗?当然 GranBurguesa 证明是IFoo<D>可以实现和构造的,所以我的回答实际上是错误的。


还有一些情况,例如 SLaks 删除的答案中暗示的情况,其中滥用通用机制导致“无限”类型。这样的类型在 CLR 中是不合法的;C# 设计团队已经考虑将类似的语言添加到 C# 编译器规范中,但还没有解决。使用这些类型可能会使编译器或运行时崩溃。

有关使编译器崩溃的无限类型的示例,请参阅我的文章:

无限但不超越


这是一个。剪切 n 将此代码粘贴到 Visual Studio 中,您会看到无法实现此接口:

interface ΙAmAPerfectlyOrdinaryInterface { }

class C : IAmAPerfectlyOrdinaryInterface { }

于 2013-05-28T04:58:00.060 回答
9

只要我们在谈论琐事,我认为这是 Eric Lippert 尝试的有效实现:

class Program
{
    static void Main(string[] args)
    {
        D test = new D();
    }
}

class C
{
    private C() { }
}

interface IFoo<T> where T : C, new() { }

class D : C
{
    public D()
        : this(5) { }

    public D(int x)
        : this() { }
}

class Dfoo : IFoo<D> { }

它编译得很好,但是StackOverflowException当你实例化时会崩溃D

于 2013-05-28T19:32:20.603 回答
7

如果您尝试排除旧接口,则可以使用ObsoleteAttribute属性标记接口。

编辑:正如@Magnus在评论中指出的那样,如果您将Error属性设置为true它的用法将导致错误。

于 2013-05-27T19:39:03.963 回答
5

如果一个类型是可访问且未密封的,那么外部代码就有可能创建该类型的实例,而基类型实际上无法对此做任何事情。不需要“完全信任”或反思。

public class CantDeriveMe
{
    private CantDeriveMe()
    {
    }
    public override string ToString()
    {
        return "My type is " + this.GetType().ToString();
    }
}

public class OhYeah : CantDeriveMe
{
    static OhYeah CapturedInstance;

    ~OhYeah()
    {
        CapturedInstance = this;
    }

    OhYeah() : this(1/String.Empty.Length)
    {
    }
    OhYeah(int blah) : this()
    {
    }
    public static OhYeah Create()
    {
        try
        {
            new OhYeah(4);
        }
        catch (DivideByZeroException)
        {
            GC.Collect();
            GC.WaitForPendingFinalizers();
        }
        return CapturedInstance;
    }
    public static void test()
    {
        OhYeah it;
        it = OhYeah.Create();
        Console.WriteLine("Result was ({0})", it);
    }
}

请注意,如果代码仅用 C# 编写,则基类析构函数在注意到对象不是合法类型时可能会发出尖叫声,但用 C# 以外的语言编写的代码将允许覆盖Finalize退出而不链接到其父母。

我认为可以指定一个开放的通用接口,其中包含struct和类约束的组合,任何类型的组合都无法满足,例如

public interface evil<T, U>
    where T : struct,U
    where U : class

不过,我不确定这种开放泛型类型是否真的有资格作为“接口”,或者是否只有封闭的泛型类型才能真正有资格作为接口(或类或结构)。

于 2013-06-01T00:28:36.687 回答