问题描述
i具有返回相同类型对象的函数(查询结果),但没有共同的属性或方法.为了使使用一个空界面作为返回类型,并在两者上"实现"了常见的I类型.
当然听起来不正确.我只能通过坚持希望有一天会有一些共同点来安慰自己,我会将这种常见的逻辑移至我的空界面.但是,我不满意,考虑我是否应该有两种不同的方法并有条件地调用.那会是更好的方法吗?
我还被告知.NET Framework使用空界面进行标记.
我的问题是:空界面是设计问题的强烈迹象还是广泛使用?
编辑:对于那些有兴趣的人,我后来发现功能语言的歧视工会是我试图实现的理想解决方案. C#似乎对这个概念还不友好.
推荐答案
尽管似乎存在一种设计模式(现在有很多提到了"标记接口"),但我相信这种做法的用法是表明代码气味的指示(大多数至少时间).
正如 @v4vendetta发布的那样,有一个静态分析规则针对以下目标: http://msdn.microsoft US/Library/MS182128(v = vs.100).aspx
如果您的设计包括预期实现类型的空接口,则您可能使用接口作为标记或识别一组类型的方法. 如果此标识在运行时发生,那么完成此操作的正确方法是使用自定义属性.使用属性或不存在属性或属性的属性,以识别目标类型. 如果必须在编译时间进行识别,则可以使用空接口.
这是引用的MSDN建议:
删除接口或添加成员.如果使用的空接口用于标记一组类型,请用自定义属性替换接口.
这也反映了已经发布的Wikipedia链接的批评部分.
标记接口的一个主要问题是,接口定义了用于实施类的合同,并且该合同均由所有子类继承.这意味着您不能"删除"标记.在给定的示例中,如果您创建了不想序列化的子类(也许是因为这取决于瞬态状态),则必须诉诸明确投掷notSerializableException(PEROCKOUTOUTPUTSTREAM DOCS).
.
其他推荐答案
您声明您的函数"根据某些情况返回完全不同的对象" - 但是它们有何不同?一个人可以成为流动作者,另一个UI类,另一个数据对象吗?不...我怀疑!
您的对象可能没有任何常见的方法或属性,但是它们的角色或用法可能相似.在这种情况下,标记接口似乎完全合适.
其他推荐答案
如果不用作标记接口我会说是的是代码气味.
一个接口定义了实现者遵守的合同 - 如果您没有不使用反射的空接口(就像标记接口一样),那么您也可以使用Object作为(已经存在的Object )基本类型.
问题描述
I have a function that returns same kind of objects (query results) but with no properties or methods in common. In order to have a common type I resorted using an empty interface as a return type and "implemented" that on both.
That doesn't sound right of course. I can only console myself by clinging to hope that someday those classes will have something in common and I will move that common logic to my empty interface. Yet I'm not satisfied and thinking about whether I should have two different methods and conditionally call next. Would that be a better approach?
I've been also told that .NET Framework uses empty interfaces for tagging purposes.
My question is: is an empty interface a strong sign of a design problem or is it widely used?
EDIT: For those interested, I later found out that discriminated unions in functional languages are the perfect solution for what I was trying to achieve. C# doesn't seem friendly to that concept yet.
EDIT: I wrote a longer piece about this issue, explaining the issue and the solution in detail.
推荐答案
Although it seems there exists a design pattern (a lot have mentioned "marker interface" now) for that use case, i believe that the usage of such a practice is an indication of a code smell (most of the time at least).
As @V4Vendetta posted, there is a static analysis rule that targets this: http://msdn.microsoft.com/en-us/library/ms182128(v=VS.100).aspx
If your design includes empty interfaces that types are expected to implement, you are probably using an interface as a marker or a way to identify a group of types. If this identification will occur at run time, the correct way to accomplish this is to use a custom attribute. Use the presence or absence of the attribute, or the properties of the attribute, to identify the target types. If the identification must occur at compile time, then it is acceptable to use an empty interface.
This is the quoted MSDN recommendation:
Remove the interface or add members to it. If the empty interface is being used to label a set of types, replace the interface with a custom attribute.
This also reflects the Critique section of the already posted wikipedia link.
A major problem with marker interfaces is that an interface defines a contract for implementing classes, and that contract is inherited by all subclasses. This means that you cannot "unimplement" a marker. In the example given, if you create a subclass that you do not want to serialize (perhaps because it depends on transient state), you must resort to explicitly throwing NotSerializableException (per ObjectOutputStream docs).
其他推荐答案
You state that your function "returns entirely different objects based on certain cases" - but just how different are they? Could one be a stream writer, another a UI class, another a data object? No ... I doubt it!
Your objects might not have any common methods or properties, however, they are probably alike in their role or usage. In that case, a marker interface seems entirely appropriate.
其他推荐答案
If not used as a marker interface, I would say that yes, this is a code smell.
An interface defines a contract that the implementer adheres to - if you have empty interfaces that you don't use reflection over (as one does with marker interfaces), then you might as well use Object as the (already existing) base type.