简体   繁体   English

我可以在C#中使用子类实现接口吗?

[英]Can I implement an interface using a subclass in C#?

given the following: 给出以下内容:

class A : B {}

interface I
{
 B TheObject {get;set;}
}

can I do this somehow? 我能以某种方式这样做吗?

class C : I
{
 public A TheObject {get;set;} 
}

note the interface has the base class and the implementation has the sub class. 请注意,接口具有基类,实现具有子类。

Give this a try 试一试

class C : I
{
 public A TheObject {get;set;} 
 B I.TheObject 
 {
   get { return A; }
   set { A = value as A; }
 }
}

You may need to modify the B setter, depending on your needs. 您可能需要根据需要修改B setter。 Implementing an interface this way has the following consequences. 以这种方式实现接口具有以下结果。 When dealing with a variable typed as a C you will not be able to access B TheObject. 处理类型为C的变量时,您将无法访问B TheObject。 If you need to you will need to declare an I variable and assign it to your C var. 如果需要,您需要声明一个I变量并将其分配给您的C var。 Implementing I this way is known as an explicit implementation. 以这种方式实现我称为显式实现。

eg 例如

C c = new C();
A a = c.TheObject; // TheObject is an A
I i = c;
B b = i.TheObject;

You can't do it because the return type of the interface implementation must match. 您无法执行此操作,因为接口实现的返回类型必须匹配。 But, my reasoning behind why you can't do it was wrong (as pointed out in the comments). 但是,我为什么不能这样做的理由是错误的(正如评论中所指出的那样)。 You must match the signature, but you can return a new A from C ... 您必须匹配签名,但您可以从C返回一个新的A ...

public class C : I
{
  public B TheObject { get { return new A(); } set {} }
}

No, you can't. 不,你不能。 At least not without C# 4.0's Covariance/Contravariance feature. 至少没有C#4.0的协方差/逆变量功能。

Nope. 不。 The compiler will complain about the type mismatch. 编译器会抱怨类型不匹配。

Also, I'm going to disagree with Paul: I don't think variance will help in your case. 此外,我将不同意保罗:我认为差异不会对你的情况有所帮助。 Take a look at what Skeet has to say about variance here . 看看Skeet 在这里对方差的看法。

No, assume the following: 不,假设如下:

class D : B {}

C c = new C();
c.TheObject = new D(); // error. D is not A, A is not D

With the above class I can still use D with objects implementing interface I , but let's assume I want to set TheObject property of an instance of C to an instance of D . 使用上面的类我仍然可以使用D实现接口I对象,但我们假设我想将C实例的TheObject属性设置为D的实例。 I can't, because D and A are siblings. 我不能,因为DA是兄弟姐妹。 They both inherit from the same class and things would be OK as they are in the interface, but declaring that you expect an A puzzles the compiler. 它们都继承自同一个类,因为它们在界面中会很好,但是声明你期望A困扰编译器。 An instance of A is not an instance of D, but instances of both A and D are instances of B. A的实例不是D的实例,但A和D的实例都是B的实例。

This rule follows Liskov Substitution Principle . 这条规则遵循Liskov替代原则

PS I want to thank Troels Knak-Nielsen for opening my mind about this subtlety. PS我想感谢Troels Knak-Nielsen对这一微妙之处的开放态度。

What you're thinking of is covariance/contravariance, but even with C# 4.0 this wouldn't work. 您所考虑的是协方差/逆变,但即使使用C#4.0,这也行不通。 It still needs to be useable if you only have a reference to the interface. 如果您只有对接口的引用,它仍然需要可用。

The getter would work, as A is also a B, but the setter wouldn't work, since the implementation expects an A, while the interface allows you to set TheObject to B. Generally, return values can be subtypes, and arguments can be base types with covariance/contravariance. getter可以工作,因为A也是B,但是setter不能工作,因为实现需要A,而接口允许你将TheObject设置为B.通常,返回值可以是子类型,参数可以是具有协方差/逆变的基类型。 But only in C# 4.0. 但仅限于C#4.0。

This compiles: 这编译:

class B { }

class A : B { }

interface I<T> where T : B
{
    T TheObject { get; set; }
}

class C : I<A>
{
    public A TheObject { get; set; }
}

But I assume this is not what you want? 但我认为这不是你想要的?

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

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