我一直在研究空接口和抽象类,从我读过的内容来看,它们通常都是不好的做法。我打算用它们作为我正在编写的小型搜索应用程序的基础。我会编写初始搜索提供程序,其他人也可以创建自己的提供程序。我的代码的意图是为那些想要实现它们的人强制实现类之间的关系。
有人可以插入并描述是否以及为什么这仍然是一种不良做法以及如果有任何替代方案可以做什么。
namespace Api.SearchProviders
{
public abstract class ListingSeachResult
{
public abstract string GetResultsAsJSON();
}
public abstract class SearchParameters
{
}
public interface IListingSearchProvider
{
ListingSeachResult SearchListings(SearchParameters p);
}
}
答案 0 :(得分:1)
空类和接口通常仅作为通用约束“可用”;这些类型本身不可用,而泛型约束通常是唯一可以将它们与其他有用的东西结合使用的上下文。例如,如果IMagicThing
封装了某些值,则某些实现是可变的,而有些则不是,一种想要记录与IMagicThing
相关联的值的方法可能会写成:
void RecordValues<T>(T it) where T:IImagicThing,IIsImmutable {...}
其中IIsImmutable
是一个空接口,其合约表明任何实现它并为任何属性报告某些值的类必须永远报告该属性的相同值。按指示编写的方法可以知道其参数在合同中有义务表现为IMagicThing
的不可变实现。
从概念上讲,如果接口的各种实现会对其行为做出不同的承诺,那么能够将这些承诺与约束相结合似乎会有所帮助。不幸的是,这种方法存在一个相当令人讨厌的限制:除非知道满足所有约束的特定类型以及从哪个对象派生,否则将不可能将对象传递给上述方法。如果只有一个约束,可以将对象强制转换为该类型,但如果有两个或更多,则无效。
由于使用约束泛型时存在上述困难,最好通过定义从IMagicThing
派生的接口IImmutableMagicThing
来表达“承诺为不可变的{IMagicThing
”的概念。但没有增加新成员。期望IImmutableMagicThing
的方法将不接受任何不实现不可变接口的IMagicThing
,即使它恰好是不可变的,但是如果有IMagicThing
的引用碰巧实现IImmutableMagicThing
,可以将该引用转换为后一种类型并将其传递给需要它的例程。
顺便提一下,我可以看到另一种用于空类类型的用法:作为身份令牌。类不需要任何成员作为字典键,监视器锁或弱引用的目标。特别是如果有一个与此类用法相关的扩展方法,为此目的定义一个空类可能比使用Object
更方便。