简体   繁体   English

非泛型接口的约束类似于泛型或AttributeUsage

[英]Constraints similar to Generics or AttributeUsage for non-generic interfaces

EDIT: This is more of a good design question that came up while refactoring and combining reusable code into a library. 编辑:这更多是一个很好的设计问题,在将可重用代码重构并将其合并到库时出现。

I am consolidating frequently used code from over the years to a library and interfaces play a large part here. 我将多年来使用的代码整合到一个库中,并且接口在这里起着很大的作用。 While refactoring, one of the main categories that interfaces are split in include whether they were designed for mutable or immutable scenarios. 重构时,接口划分的主要类别之一包括它们是为可变场景还是不可变场景而设计的。 Consider the following: 考虑以下:

Mutable and Immutable: 可变和不可变:

interface ICloneable<T> { T Clone (); }

Immutable: 一成不变的:

interface ISomeInterface { T SomeFunc (); }

Mutable 易变的

interface IInitializable { void Initialize (); }
interface ICopyable<T>: IInitializable { T CopyFrom (T source); T CopyTo (T destination); }

The case of IInitializable is the odd one out as there is no reason for it to accept a generic parameter. IInitializable的情况很奇怪,因为没有理由接受通用参数。 However, without one, it cannot enforce usage with classes only. 但是,如果没有一个,它就不能仅强制使用类。

I assume that constraints do not exist for non-generic types so the question is whether there is a way to enforce this at runtime (or better at compile time)? 我假设非泛型类型不存在约束,所以问题是是否有一种方法可以在运行时强制执行(或在编译时更好)? Besides generics, attributes can also be restricted (not that it matters here). 除了泛型外,属性也可以受到限制(在这里并不重要)。

Of course I could just make the interface generic but that wouldn't be a good enough reason would it? 当然,我可以使接口通用,但这不是一个足够好的理由吗? Any elegant way to achieve this? 有什么优雅的方法可以做到这一点吗?

There is no way in the C# language to prevent a struct from implementing your interface. C#语言无法阻止struct实现您的接口。 Any type is free to implement any interface so long as it can satisfy the methods described there. 任何类型都可以自由实现任何接口,只要它可以满足此处描述的方法即可。

However you can constrain the usages of IInitializable to only work with implementations that are class types. 但是,您可以限制IInitializable的用法, IInitializable仅与class类型的实现一起使用。 For example 例如

void M<T>(T value) where T : IInitializable, class 

This can be used to constrain your usage scenarios to class only and hence get the guarantee you are looking for 这可以用来限制您的使用情景,以class唯一,因此得到你正在寻找的保证

Your code looks like Java. 您的代码看起来像Java。

C# supports operator overloading and user-defined conversions, so your ICopyable<T> seems redundant. C#支持运算符重载和用户定义的转换,因此您的ICopyable<T>似乎是多余的。

Also, unless you really need a generic Clone() method, you're probably just as well-off defining copy constructors; 另外,除非您确实需要通用的Clone()方法,否则定义复制构造函数可能同样有用。 you can always use double-dispatch internally. 您始终可以在内部使用双调度。 By 'really need', I mean, is the algorithm truly generic? 我的意思是说,“真正需要”是真的泛型吗?

Edit: Clonable in Java was a kludge to get around the fact that it didn't support templates/generics. 编辑: Java中的Clonable可以绕开它不支持模板/泛型的事实。 C# does, so your algorithm can match on type and you can use simple-to-use copy construtors. C#可以,因此您的算法可以在类型上匹配,并且可以使用简单易用的复制构造函数。

Finally, WRT to Initialize() , if it's a generic no-argument method, why not just put the code in the constructor? 最后,将WRT Initialize()Initialize() ,如果这是一个通用的无参数方法,为什么不将代码放入构造函数中呢? It's going to be far easier for people to use and understand. 人们将会更容易使用和理解它。 If your object is only partially inialised at contruction, then you need to check and throw InvalidOperationException s anyway, so why complicate your interface? 如果您的对象仅在构造时被部分初始化,那么无论如何您都需要检查并抛出InvalidOperationException ,为什么还要使接口复杂化?

If the Initialise() method is to support polymorphism, then it shouldn't be in an interface, as it's an implementation detail - interfaces are about how people use your objects, no how you build them; 如果Initialise()方法要支持多态,则它不应该位于接口中,因为它是实现的详细信息-接口与人们如何使用您的对象有关,而与您如何构建它们有关; the fact that that the compiler does some checks on them is secondary to their purpose. 编译器会对它们进行一些检查是其目的的第二要务。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM