空接口用于什么?

7

我正在处理的代码有一个空接口:

public interface ICube {}

它没有方法或属性。

一些类实现了 ICube 接口,其他接口继承自 ICube
请有经验的人告诉我,ICube 接口有什么好处?


空接口是代码异味吗? - Hien Nguyen
请问您能否分享一些代码?这是作业的一部分吗?还是练习题?任务是什么?想法是什么? - Edwardcho Vaklinov
2个回答

11

请阅读MSDN关于接口设计的内容。

https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/interface

✓ 如果您需要支持一组类型(其中包括值类型)的共同API,则应定义一个接口。

✓ 如果您需要在已继承某个其他类型的类型上支持其功能,则可以考虑定义一个接口。

X 避免使用标记接口(没有成员的接口)。

如果您需要标记一个类具有特定的特征(标记),通常使用自定义属性而不是接口。

✓ 至少提供一个实现接口的类型。

这样做有助于验证接口的设计。例如,List是IList接口的实现。

✓ 至少提供一个使用您定义的每个接口的API(以接口作为参数的方法或以接口作为类型的属性)。

这样做有助于验证接口设计。例如,List.Sort消耗System.Collections.Generic.IComparer接口。

X 不要向先前发布的接口添加成员。

更多参考: 空接口 Are empty interfaces code smell?

标记接口 什么是标记接口的目的?


6
这被称为“标记接口”。有时它们用于指示一个类的特定目的,但这不是一种理想的做法。
虽然我曾经使用过标记接口,但下面是它们所创建的问题的说明。假设我有一个List<ICube>。也许我作为方法参数收到它。
public interface ICube {} // It's empty!

public void DoSomethingWithTheseCubes(List<ICube> cubes)
{
    foreach(var cube in cubes)
    {
        // what do I do with this cube?
    }
}

您可以看到我卡住了。 ICube 只是一个标记接口,因此它本身没有任何方法或属性。我无法对其进行任何操作。这可能会导致我将每个立方体强制转换为其他类型,以便可以对其进行某些操作。

public void DoSomethingWithTheseCubes(List<ICube> cubes)
{
    foreach(var cube in cubes)
    {
        (SomeOtherType)cube.DoSomething();
    }
}

但如果我进行类型转换,就会引发运行时错误,因为我可能无法确定每个对象的实际运行时类型。如果我知道运行时类型,那么我应该这样做:

public void DoSomethingWithTheseCubes(List<SomeOtherType> things)
{
    foreach(var thing in things)
    {
        thing.DoSomething();
    }
}

我们并不确定是否存在这个问题,但使用标记接口会引发它。这是在将接口用于其意图之外的东西。它更像是一个属性甚至是一个注释。
接口有两个作用,它们共同工作:首先,它描述了类实现的成员。其次,它允许我们将实现接口的类强制转换为该接口。标记接口都不具备这两个作用。它们只允许我们将对象转换为没有成员的类型。这最多是无用的,而在最坏的情况下,它会导致更多可疑的类型转换。

那么有什么替代方案吗?因为即使是微软也在这样做。例如:IAuthorizationRequirement。 - mightycode Newton
就像许多事情一样,我已经稍微缓和了我的观点。如果我们在接口中唯一要做的事情是检查 if (thisThing is ISomeType),但没有其他转换,那么这并不是很糟糕。对我来说,属性更有意义。 - Scott Hannen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接