【问题标题】:Static member inheritance in C#, what is the best way?C#中的静态成员继承,最好的方法是什么?
【发布时间】:2012-07-03 11:41:41
【问题描述】:

解决这个问题的最佳方法是什么?

静态成员是所有子类的成员,我希望子类使用不同的静态成员,但名称相同,这样我就可以使用 vehicle.canDo;这应该给我不同的数组,具体取决于车辆实例的真正类别。

我可以从 canDo 数组中删除静态,但是同一子类的所有实例在 canDo 数组中应该始终具有相同的值,因此不需要在每个实例中都有 canDo 数组,这将浪费大量内存,因为我会有太多此类的实例。

class Vehicle {
    public static List<string> canDo;

    static Vehicle() {
        canDo = new List<string>(); 
        canDo.Add("go");
    }
}

class Plane : Vehicle {
    static Plane() {
        canDo.Add("fly");
    }
}

class Ship : Vehicle {
    static Ship() {
        canDo.Add("sail");
    }
}



class Main {
    static void Main(string[] args) {
        Vehicle plane = new Plane();
        Vehicle ship = new Ship();

        plane.canDo; // Contains (go, fly and sail) i want only (go and fly)
        ship.canDo; // Contains (go, fly and sail) i want only (go and sail)
    }
}

【问题讨论】:

  • 突然想到,从 canDo 中删除 'static' 限定符应该可以解决这个问题
  • Mustafa,我认为在保持属性静态的同时实现这一目标是不可能的。事实上,当在任何item(方法、属性、类)中使用static时,这个item将只有一个instance(实际上是一种) 用于整个应用程序(这很重要,它们将具有相同的生命周期)。
  • Is it possible to create variable in parent class, that would initialized once per derrived type? 的可能重复项虽然措辞非常不同但问题是相同的

标签: c# inheritance static


【解决方案1】:

解决这个问题的最佳方法是什么?

不要对非静态的事物滥用静态方法。就这么简单。

静态没有继承,也不是可以以任何方式具有继承场景的东西。

您正在通过滥用一项功能进行战斗 - 不值得战斗。请学习正确的面向对象。

【讨论】:

  • 实现类级(非实例级)数据而不一遍又一遍地重复代码的“正确”方法是什么?
  • 不要这样做。几乎实现单例。在需要的地方引用容器实例。您可以重复方法/引用,但不能重复实例数据。
  • 如果它能让您的工作更轻松,为什么不呢?我不是为了写 OO 代码而写 OO 代码——我写 OO 代码是因为它应该帮助我很好地解决问题。如果它不能很好地帮助解决问题,它就达不到它的目的,我会不用它来自动化这个过程。作为记录,JonSkeet 在这里为类似问题提出了一个很好的解决方案:stackoverflow.com/a/13631714/483347
  • 或者你实现了非常好的类设计,可以在未来节省你的时间。我并不是说我什么都懂,我只是拒绝“因为事情不是这样完成的”作为为什么某事不应该被完成的最终答案。
  • 我不知道神户牛排与任何事情有什么关系,但就个人而言,如果我需要绕过一种语言的缺失功能(或反功能)并且我可以可持续地做到这一点,我会的。欢迎你做你喜欢的事。
【解决方案2】:

请注意,您还可以使用 new 隐藏基类的 canDo

class Vehicle
{
    public static List<string> canDo = new List<string>() { "go" };   
}

class Plane : Vehicle
{
    public new static List<string> canDo = new List<string>(Vehicle.canDo);
    static Plane()
    {
        canDo.Add("fly");
    }
}

【讨论】:

    【解决方案3】:

    你不需要静态变量和构造函数,只需添加基本构造函数(默认完成,: base() 是可选的):

    class Vehicle {
        public List<string> canDo;
    
        Vehicle() {
            canDo = new List<string>(); 
            canDo.Add("go");
        }
    }
    
    class Plane : Vehicle {
        Plane() : base() {
            canDo.Add("fly");
        }
    }
    
    class Ship : Vehicle {
        Ship() : base() {
            canDo.Add("sail");
        }
    }
    

    更新:基于@Eben Roux 的评论 -

    public abstract class Vehicle {
        protected static List<string> _canDo;
        protected abstract List<string> getCanDo();
        public List<string> canDo{
            { get {
                   var _cando = new List();
                   _cando.AddRange(Vehicle._canDo);
                   _cando.AddRange(this.getCanDo());
                   return _cando;
                  }
            }
        }
        static Vehicle() {
            _canDo = new List<string>(); 
            _canDo.Add("go");
        }
    }
    
    class Ship : Vehicle {
        protected static List<string> childCanDo;
        protected override getCanDo(){
            return Ship.childCanDo;
        }
        static Ship() {
            childCanDo.Add("sail");
        }
    }
    

    【讨论】:

    • OP 担心这样一个事实,即 Ship 的每个实例都有自己的 canDo 集合,并且实际上每个实例都复制了它(希望这是有道理的)。如果您不会有很多实例,那没有错;否则状态可以通过以某种方式注入 canDo 集合/或检索它来共享。
    • @EbenRoux - 感谢您的解释。我错过了这一点。那么你仍然可以保留静态基列表,并与子类连接......我已经更新了答案......我没有测试过代码,但希望这个想法很清楚......
    • ...但是继承的整个想法在这里都消失了...正如其他答案中所说-静态在这里没有位置。
    • 同意 :) --- 然而,我认为静力学确实有它们的位置,但它需要一些仔细的考虑和设计。
    【解决方案4】:

    您需要每个类型的canDo 列表的实例。因此,您可以通过构造函数传入集合,也可以在子类型级别使用静态。

    编辑(详细说明):

    由于您的子类实例都具有相同的“能力”,并且您不想为每个都填充一个列表,因此您需要一个共享列表。您在可能需要组合的地方使用继承:

    public abstract class Vehicle
    {
        protected List<string> canDo;
    
        protected Vehicle(List<string> canDo)
        {
            this.canDo = canDo;
        }
    }
    
    public class Plane : Vehicle
    {
        public Plane(List<string> canDo) : base(canDo)
        {
        }
    }
    

    我也不会使用List&lt;string&gt;,而是将其封装在一个具有商业意义的类中(尽管我知道这只是一个示例)。要填充 canDo 列表,您可以使用工厂或子类型上的工厂方法。

    有很多方法可以做到这一点,您需要找到舒适的东西。

    虽然我确实提出了一个静态作为替代方案(因为你在问它),但我自己绝对不会为此使用静态。

    【讨论】:

    • 最初的意图不是将数据保留在类级别,而不是实例级别吗?除非我有误解(当然是合理的),否则这会破坏目的......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-10
    • 1970-01-01
    • 2010-10-06
    相关资源
    最近更新 更多