【问题标题】:C# Override abstract property with concrete propertyC# 用具体属性覆盖抽象属性
【发布时间】:2017-08-26 07:12:09
【问题描述】:

所以我有这个抽象类。其中有一个抽象类型列表

public abstract class BaseClass
{

    public abstract List<A> History { get; set; }

和继承者类。

public class ConcreteClass : BaseClass
{
    public override List<B> History { get; set; }

我的问题很简单。为什么这会返回错误。 A 是 b 继承的抽象类。那么为什么我不能让一个具体的属性覆盖一个抽象的属性呢?

注意:由于其他问题,我不能在基类中使用泛型。在这个问题上有所澄清。我正在使用 mvc,由于动态类型的一些问题,我不能说 BaseClass&lt;t&gt; 在其他一些领域,调用 GetHistory() 方法的方法需要它返回具体列表而不是抽象列表。所以我被困在岩石和坚硬的地方之间。

【问题讨论】:

  • 因为如果我这样做BaseClass c = new ConcreteClass();,那么我必须能够将Aany 子类的实例添加到c.History
  • 嗯,这取决于你想要做什么。你能退后一步,描述一下你想用这个解决什么问题吗?
  • AB 是否都实现了相同的接口?如果它们以类似的方式使用,那么可能存在一些相似之处。在这种情况下,您可以将列表设为 IHistory 或其他类型。 List&lt;IHistory&gt; History { get; set;}
  • @trinityalps:您还没有真正添加到问题中,您实际上想要做什么。或者详细说明“MVC 中的动态类型问题”是什么意思。
  • Why does this return an error. 在这种情况下,与我们分享编译器错误很重要。它让帮助您变得更加轻松。

标签: c#


【解决方案1】:

为什么这会返回错误。 A 是 B 继承的抽象类。

再一次。几乎每天都会有人问这个问题。

abstract class Fruit 
{
  public virtual List<Fruit> M() { return new List<Fruit>(); }
}
class Apple : Fruit
{
  public override List<Apple> M() { return new List<Apple>(); }
}

假设这是合法的。出了什么问题?

class Banana : Fruit { }

...

Fruit f = new Apple(); // Legal
List<Fruit> bowl = f.M(); // calls Apple.M, returns a list of apples.
bowl.Add(new Banana());

现在碗里有一根香蕉,里面可能只有苹果。

这就是为什么这是非法的。搜索协变和逆变,了解这种转换在 C# 中何时合法,何时非法。简而言之,只有当编译器能够证明它是安全的并且类型参数是引用类型时它才是合法的。

现在,这个呢?

abstract class Fruit 
{
  public virtual Fruit N() { return new Banana(); }
}
class Apple : Fruit {
  public override Apple N() { return new Apple(); }
}
...
Fruit f1 = new Apple();
Fruit f2 = f1.N(); // No problem, an apple is a fruit.

这不会破坏类型系统;这将是安全的,但它仍然是非法的。这是非法的,因为 virtual return type covariance 从未在 C# 中实现过。它是用 C++ 实现的。

它尚未实现,因为它从来都不是 C# 团队的高优先级。十多年来,人们一直在要求它,但这并不是一个很棒的功能。也许最终会完成;如果您对此有强烈的感觉,请加入 github 上的论坛并为之鼓吹。

【讨论】:

【解决方案2】:

您可以考虑的一种方法是:

public class ConcreteClass : BaseClass<ListClass>
{
    public override List<ListClass> History { get; set; }
}

public abstract class BaseClass<T> where T : BaseListClass
{
    public abstract List<T> History { get; set; }
}

public abstract class BaseListClass
{
}

public class ListClass : BaseListClass
{
}

通过让具体类指定它想要使用的确切泛型类型(re:基本类型),那么它可能适合您的目的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-02
    • 2011-08-14
    • 2023-03-04
    • 1970-01-01
    相关资源
    最近更新 更多