【问题标题】:C#: How can I set a maximal Value of a property from a derived class? (And not in base class)C#:如何从派生类中设置属性的最大值? (而不是在基类中)
【发布时间】:2021-01-26 17:04:50
【问题描述】:

CannibalGhost : Ghost(来自 Ghost 的 CannibalGhost dervies)

CannibalGhost 可以吃掉任何种类的幽灵,并将它们的高度加到他的高度上。但是Ghosts 应该可以任意大,而CannibalGhosts 的最大高度应该是 50。在任何情况下都不能超过。不是通过。 set-accessor 而不是通过构造函数。

到目前为止我已经尝试过:

  • 覆盖Constructor:

    无法覆盖构造函数

  • Set-Accessor 中实现 if(height >= 50)

    如果我在 Main-Program 中使用构造函数创建对象,则不起作用

  • 在 Main-Code 中实现一个屏障,使高度永远不会超过 50

    如果我以后想要CannibalGhost 的新对象,则不起作用(而且很乱)

  • 写成 CannibalGhost 不是从 Ghost 派生的

    所以我可以编写一个新的构造函数和set-Accessor,上限为 50。 它有效,但我希望 CannibalGhosts 也成为一个 Ghost(源自 Ghost)

总结: 如何将CannibalGhost 的属性Height 设置为最大50,但不在基类Ghost 中?

【问题讨论】:

标签: c# oop properties max overriding


【解决方案1】:

您可以构建Ghost,使其知道派生类中需要一些验证,而无需在基类中实现逻辑本身

public class Ghost
{
    private int height;

    protected virtual bool IsValidHeight(int newHeight)
    {
        return true;
    }

    public int Height
    {
       get{ return height; }
       set
       {
           if(!IsValidHeight(value) throw new InvalidHeightException(value);
           height = value;
       }
    }
}

public class CannibalGhost 
{
    protected override bool IsValidHeight(int newHeight
    {
        return newHeight <= 50;
    }
}

也许您不想抛出异常,而是限制您可以创建该虚拟方法的高度

protected virtual int LimitHeight(int newHeight)
{
     return newHeight;
}

protected override int LimitHeight(int newHeight)
{
    return (int)Math.Min(newHeight,50);
}

那么二传手就是

set
{
    height = LimitHeight(value);  
}

这对Ghost 没有影响,但会将派生的CannibalGhost 限制为50。


事实上,这不是一个很好的解决方案。在设计基类时,您无法知道所有可能需要这种验证的地方 - 这就是继承在比这个简单示例更复杂的解决方案中失效的原因。

CannibalGhost 真的Ghostis-a 关系吗?或者它实际上是由多个Ghost 实例组成的(has-a-collection-of 关系)。在这种情况下,它的高度可能只是其所有组成的 Ghost 实例的总和,限制为 50。不需要继承。也许所有的幽灵都为共享行为实现IGhost - 需要考虑的事情!

【讨论】:

  • 我很想使LimitHeight()受保护。
  • @MatthewWatson bah 这里所有的虚拟/覆盖方法都应该是protected - 谢谢好地方。愚蠢的错误
【解决方案2】:

通过在基类中设置高度属性virtual,您可以通过覆盖它让派生类实现更具体的行为。

例子:

public class Ghost
{
    public virtual int Height { get; set; }
}

public class CannibalGhost : Ghost
{
    private int _height;
    public override int Height
    {
        get
        {
            return _height;
        }
        set
        {
            if (value > 50)
                throw new InvalidOperationException($"A {nameof(CannibalGhost)} cannot have a height over 50");

            _height = value;
        }
    }
}

【讨论】:

  • 如果您想在基类构造函数中初始化Height,使用这种方法需要注意一个问题。在那种情况下,你会成为making a virtual member call from a constructor,这很糟糕。
  • @MatthewWatson 正确。如果有人发现自己处于这种情况,那么我会将_height 字段移动到基类中并使其受到保护。然后你可以直接从构造函数中设置它而无需担心。
猜你喜欢
  • 2015-08-26
  • 1970-01-01
  • 1970-01-01
  • 2019-08-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-23
相关资源
最近更新 更多