接口继承。不实现接口错误。

4

我需要使用继承接口,但遇到了问题。我将在下面的示例中解释我的问题。假设我有接口IFlyable

public interface IFlyable
{
    IVerticalSpeed Speed { get; set; }
}

它包含了IVerticalSpeed接口。我创建了另一个接口叫做ISpeed,它继承自IVerticalSpeed接口:

public interface ISpeed : IVerticalSpeed
{
    int MaxSpeed { get; set; }
}

在下一步中,我创建了一个类Fly,该类实现了IFlyable接口:
public class Fly : IFlyable
{
    public IVerticalSpeed Speed { get; set; }
}

一切都很好...但是如果我想要将IVerticalSpeed接口替换为继承自IVerticalSpeed接口的ISpeed接口怎么办?

public class Fly : IFlyable
{
    public ISpeed Speed { get; set; }
}

我认为一切都应该没问题,因为我的ISpeed接口是IVertialSpeed接口加上任何ISpeed接口所包含的内容。但是这不是正确的。我收到了一个错误,说:“Fly未实现接口成员IFlyable.Speed(...)。为什么?

2
你没有展示IVerticalSpeed。 - Seabizkit
1
可能是为什么C#接口不能包含字段?的重复问题。 - cokceken
@Seabizkit - 不,但这不应该有影响。interface IVerticalSpeed {}就足够了。 - H H
在Adam,没有更多信息是没有帮助的。我无法确定IVerticalSpeed是否作为属性存在...很奇怪,但问题也是如此,所以要求人们在有限的信息下提供帮助并不能完整地描述情况。因此,答案是Fly不再实现IVerticalSpeed作为属性,这是由“IFlyable”表示的。 - Seabizkit
5个回答

4
所有答案都向您展示了可能的解决方案,但实际上没有一个回答了这里重要的问题:
我认为一切都应该没问题,因为我的ISpeed接口是IVerticalSpeed接口加上任何ISpeed接口所包含的内容。但那是不正确的。我得到了一个错误,它说:"Fly未实现接口成员IFlyable.Speed(...)。为什么?
您自己已经说了。ISpeed是IVerticalSpeed,但并非所有IVerticalSpeed都是ISpeed,因此您根本没有满足合同。
如果您的代码被允许,并且我想执行以下操作,会发生什么:
public interface IMyOtherSpeed: IVerticalSpeed { ... }
IFlyable myFly = new Fly();
IMyOtherSpeed mySpeed = new MyOtherSpeed();

myFly.Speed = mySpeed; //Runtime error, mySpeed is not an ISpeed?!?

现在你明白问题了吗?你会违反接口的合约,因为你的类只接受ISpeed,而它应该接受任何IVerticalSpeed


1
另一种强调方式:set破坏了合同,而OP正在推理get部分。 - H H

2
如果您使用泛型,可以这样做:
public interface IFlyable<out T> : where T IVerticalSpeed
{ T Speed {get;set;} }

然后在你的类中,你需要做出类似以下的操作:
public class Fly : IFlyable<SomeSpeedClass>
{
  public SomeSpeedClass Speed{get;set}
}

你认为飞机是一个垂直速度的飞机吗?仅仅因为使用泛型是可能的,并不意味着应该这样做。说实话,这个特定的例子似乎不适合泛型。 - InBetween
@InBetween,这个问题最好的解决方法是什么?因为Fly类必须实现IFlyable接口,但他希望在Speed属性中返回一个ISpeed实例,而不是一个IVerticalSpeed实例。 - dcg
如果没有上下文,我无法回答最佳方法是什么。但可以合理地期望IFlyable将具有类似于HorizontalSpeedHorizontalAccelerationVerticalAcceleration等属性。你要创建一个IFlyable<T1, T2, T3, etc>接口吗?而且,让我们不要开始处理通用类型差异的问题……这一切都会变得非常混乱。泛型不应该只是为了使类型系统工作而成为解决方案。 - InBetween

1

取而代之

public class Fly : IFlyable
{
    public ISpeed Speed { get; set; }
}

你应该匹配 IFlyable 接口。
public class Fly : IFlyable
{
    public IVerticalSpeed Speed { get; set; }
}

接口不是继承,必须完全匹配。

编辑:让我重新表述,实现其他接口的接口不是继承,因此会出错。接口必须完全匹配,这就是为什么会引发错误(ISpeed!= IVerticalSpeed)。


因为@InBetween的回答更清晰,尽管两个回答都试图回答相同的问题,因此给其点赞。 - Cleptus

1
因为您的属性的签名必须保持100%不变。您可以实现一个新的属性作为解决方法,但它也有其限制。

如果您的继承方式可以双向工作,那么您可以这样做。您已经知道,所有ISpeed都是IVerticalSpeed。但反过来就不是这样了。并非所有的IVerticalSpeed都是ISpeed。所以我们可以给您的类添加另一个方法,但在那一点上它将面临一个问题:

  public interface IVerticalSpeed
  {
    int Value { get; set; }
  }

  public interface IFlyable
  {
    IVerticalSpeed Speed { get; set; }
  }

  public interface ISpeed : IVerticalSpeed
  {
    int MaxSpeed { get; set; }
  }

  public class Fly : IFlyable
  {
    public ISpeed Speed { get; set; }

    IVerticalSpeed IFlyable.Speed
    {
      get
      {
        return this.Speed;
      }
      set
      {
        // Wow, wait, you want to SET an IVerticalSpeed,
        // but not every IVerticalSpeed is an ISpeed... what now?
        // this.Speed = value;
      }
    }
  }

这不是代码问题,而是设计问题。如果有人将 IVerticalSpeed 设置到你的 Fly 中,你想做什么?因为你的接口允许这样做。也许你不想使用设置器?

0

你没有展示IVerticalSpeed,但如果你能控制它,请考虑

public interface IFlyable<out TSpeed>
    where TSpeed : IVerticalSpeed
{
    TSpeed Speed { get; set; }
}

然后在 Fly 中实现如下:

public class Fly : IFlyable<ISpeed>
{
    public ISpeed Speed { get; set; }
}

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