【问题标题】:I don't understand inheritance with base classes我不明白基类的继承
【发布时间】:2021-05-02 03:59:26
【问题描述】:

我对继承的理解非常基础。

我想创建一个基类,它实现IDisposable,然后让其他具有功能的类从该基类继承,以便它们共享一个基类型。

它将允许我将每个对象放入一个列表中,以便我可以在需要清理时一次性处理所有内容。 问题是,C# 中的类只能继承一次,否则只能使用接口。

现在,像Thread 这样的类如何从我的基类继承而无需我基本上重新编写Thread 类的代码?

这听起来可能很愚蠢,但简而言之:我想让已经存在的类继承我选择的基类,而不会失去它的功能。 (这样一个项目中使用的所有类都有一个共同的基础,可以总结为一种对象类型,例如List)

这可能吗?

【问题讨论】:

  • 问题是,C# 中的类只能继承一次,否则只能使用接口 - 谁告诉你的?继承树的深度没有实际限制
  • 我想让已经存在的类继承我选择的基类 - 您是否编写了这些“已经存在”的类? 像 Thread 这样的类如何从我的基类继承而无需我对 Threadclass 进行基本编码 - 他们不能
  • 每个类只能继承一个基类,但下一个类可以继承该类和下一个类。没有真正的限制。
  • 这有可能吗? - c# 中的所有内容都已经从 Object 继承,但是如果没有另一个类的源代码,您就不能编写代码来更改另一个类所继承的内容
  • @CaiusJard 不,他指的是 .Net 框架中的对象。

标签: c# inheritance interface subclass base-class


【解决方案1】:

你给的例子是 invlolves 接口IDisposable。在 C# 中,类可以实现多个接口。

另一方面,在 C# 中,类可能继承自恰好一个类。

话虽如此,从类继承并不总是好主意,因为它非常有限。相反,我会建议作文:wiki

例如,我会建议类似组合设计模式(这是一个小变化,因为组合没有对象集合,而只有一个对象):

public interface IFoo
{
    void DoFooStuff();
}

public class Foo : IFoo
{
    public void DoFooStuff() {...};
}

public class ShouldImplementFoo : IFoo
{
    // Composition, you need to initialize it some time
    private Foo _foo;
    
    public void DoFooStuff() { _foo.DoFooStuff(); }
}

编辑

重新考虑您的问题后,您似乎想将一组(不同类的)对象放在一个列表中,这样您就可以对列表中的每个对象执行一些定义的操作。 p>

最简单的是:用你定义的动作定义接口:

public interface IMyIntf
{
    void MyDesiredAction();
}

现在,让所有类都实现它。现在你可能会想“好吧,现在我需要在任何地方实现这个方法......” - 不是那样的!只需使用适配器设计模式,例如,有类:

public class MyConcreteClass
{
    public void ActionIWishToExecuteOnThisObject() 
    { ... }
}

您只需将其修改为:

public class MyConcreteClass : IMyIntf
{
    public void ActionIWishToExecuteOnThisObject() 
    { ... }

    // implement interface
    public void MyDesiredAction()
    {
        ActionIWishToExecuteOnThisObject();
    }
}

现在,您可以使用一些聚合,例如List<IMyIntf>,将您感兴趣的所有对象放在那里并执行:

foreach(var item in myList)
    item.MyDesiredAction();

【讨论】:

    【解决方案2】:

    一个类可以继承自一个祖先类(否则是 Object,所有的根)。

    它还可以实现一些接口(或没有)。

    一个类可以有未实现的抽象成员,因此该类是抽象的。

    成员也可以是虚拟的以启用多态性(抽象成员是)。

    一旦实现,类中就有一个东西可用,即使不是抽象的也可以被实例化,并且对所有子类也可用,除了那些隐藏在子类中的私有对象。

    无需重复,这就是 OOP 的力量之一。

    这样做,使用抽象,封装,继承和多态,在研究了现实世界和我们工作的领域之后,我们可以设计这个现实世界的投影,我们脑海中的一个视图,具有数据的概念(字段和属性)和操作(方法),分为工件(对象)和关系、组合、聚合、接口、组件、控件等。

    因此我们可以将处理分解为不重复,例如:

    • 有一个Animal 类和Cat 和Dog 子类,
    • 我们在动物中添加了Size 和Color 方面,
    • 以及为所有动物实现的 Eat 和 Walk 方法,
    • 还有一个未实现的抽象DoSound。

    因此:

    • 在具体的类Cat 和Dog 中我们不再实现这些东西,
    • DoSound 除外,它适用于每种真实的动物性别。

    关于接口,它们是虚拟合约。

    例如,我们可以让动物和建筑物乍一看没有任何共同之处(我们不会回到原子和光子),但我们也希望能够管理像猫和狗这样的对象实例作为房子和博物馆拍照。

    为了实现我们定义了一个接口IPhotoTaking,并且在定义以前的类时,我们添加了它们实现了这个接口。

    代码示例:

    public interface IPhotoTaking
    {
      Image TakePhoto();
    }
    
    public abstract class Animal : IPhotoTaking
    {
      public int Size { get; set; }
      public Color Color { get; set; }
      public void Eat() { ... }
      public void Walk() { ... }
      public abstract void DoSOund();
      public Image TakePhoto();
    }
    
    public class Cat : Animal // no need to repeat IPhotoTaking
    {
      public override void DoSound() { ... }
    }
    
    public class Dog : Animal
    {
      public override void DoSound() { ... }
    }
    
    public abstract class Building :IPhotoTaking
    {
      public Image TakePhoto();
    }
    
    public class House : Building
    {
    }
    
    public class Museum : Building
    {
    }
    

    现在有了这个列表,我们可以像这样使用多态性:

    var animals = new List<Animal>();
    
    foreach ( var animal in animals )
      animal.DoSound();
    

    同样没有多态性,并且由于 C# 不支持真正的多态性,钻石运算符尚未应用于 List&lt;&gt; 这里,我们可以使用这样的接口:

    var items = new List<IPhotoTaking>();
    
    foreach ( var item in items )
      item.TakePhoto();
    

    备注:如果每种类型的拍照可能不同,我们可以将其设置为 virtual 以专门针对每种类型的实现。

    OOP Basic Principles

    What is abstraction in C#?

    How to choose between public, private and protected access modifier?

    Association, Composition and Aggregation

    What is polymorphism?

    What is the difference between an interface and a class?

    About the lack of true generic polymorphism and the missing diamond operator in C#

    【讨论】:

    • 谢谢你的解释很有帮助,不幸的是我只能标记一个答案,但你的答案也非常好:)!
    • @Rakku 只需选择一个最能向您解释事情并帮助您以您感觉最好的方式实现目标的简单、干净、简短、可理解、可维护、优雅、健壮、安全和良好的没有意大利面也有效。
    【解决方案3】:

    如果您的目标是简单地存储可以处理的对象列表,那么您需要List&lt;IDisposable&gt;。任何直接或间接实现该接口的类都可以存储在其中。

    var disposables = new List<IDisposable>();
    disposables.Add(new MyClass1());
    disposables.Add(new SomeClass());
    disposables.Add(new AnotherClass());
    
    disposables.ForEach(d => d.Dispose());
    

    这是否值得模式,我不服!

    【讨论】:

    • 哇,我不知道我可以将接口用作列表类型!那是一个很好的捷径。你会用什么样的模式来清理?
    • 不是这个!问题是你很少有一个完全不同的随机类列表需要一次性清理。无论哪个类实例化一个对象,都应该负责之后的清理工作。
    • 啊,现在我明白误会在哪里了。我不想使用这种模式来清理完整的类。此模式用于每个类中,该类清理我实例化的组件。该列表包含组件,而不是整个类。我的想法是,我必须为不共享共同父级的组件创建一个以上的列表(实现了 IDisposable)。但是由于我现在可以将所有内容放在一个仅使用界面的列表中,因此我遇到的问题已经消失了。
    • @Rakku 如果您找到了问题的答案,请将其中一个答案标记为已接受。
    猜你喜欢
    • 2019-09-09
    • 2012-11-28
    • 2022-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多