【问题标题】:How to use abstract base class properly C#如何正确使用抽象基类 C#
【发布时间】:2012-03-16 11:13:05
【问题描述】:

您好,我正在用 C# 创建一个几何库...

我有一个抽象类形状。 我已经定义了一个类向量(也代表 (x,y) 点)。

我想使用各种几何对象、曲线、直线、圆弧、路径等

为此,我定义了一个抽象 Segment 类并派生了许多类,例如LineSegment(见下文)、CurveSegmentArcCircleSegmentBezierCurveSegmentHalfInfiniteLine

我还定义了一个类Path(不是抽象的),它旨在表示连接在一起的多个段(就像您可能从绘图应用程序中得到的一样)。在此,我包括了 Segments 的 List 成员 (List<Segment>)。

然后我希望从Path 派生类,关键示例是LinePath,它应该只包含LineSegments。我遇到的问题是我希望能够在LinePath 对象上调用get 属性,假设它将返回LineSegment。如果不每次都显式转换,这可能吗?

我想避免使 Path 抽象,因为我可能有多个 Segment 类型的路径。

public class LineSegment : Segment 
{
    private vector m_start;
    private vector m_end;
    private vector m_vector;

    public vector Start
    {
        get { return m_start; }
        set { m_start = value; }
    }

    public vector End
    {
        get { return m_end; }
        set { m_end = value; }
    }

    public vector Vec
    {
        get { return m_vector; }
        set { m_vector = value; }
    }

    public double Length()
    {
        return Vec.length();
    }

    public LineSegment(vector v0, vector v1):base()
    {
        this.Start.x = v0.x;
        this.Start.y = v0.y;
        this.End.x = v1.x;
        this.End.y = v1.y;

        this.Vec = this.End - this.Start;
    }
}

【问题讨论】:

  • 作为一个想法,而不是将Path 重载到LinePath,您是否可以使用Path<T>,然后根据需要创建Path<Segment>Path<LineSegment>。我并没有认真考虑这是否会奏效,但似乎它可能会奏效。 :)

标签: c# oop abstract-class


【解决方案1】:

如果我正确理解你想要什么,你可以这样做:

使你的路径类通用

public class Path<T> where T : Segment
{
    private IList<T> segments = new List<T>();

    public IList<T> Segments { get { return this.segments; } }
}

然后您可以创建 LinePath 对象

public class LinePath : Path<LineSegment>
{
}

这样,您可以确保LinePath.Segments 中的所有段都是LineSegments,同时仍然可以将Path 类重新用于任何与Segment 对抗的操作。

【讨论】:

  • 但是这样你就不能同时拥有不同 Segment 类型的 Path。
  • 您可以通过创建非通用版本的路径公共类 Path : Path 然后可以包含任何类型的段。
  • 谢谢...这似乎是一个很好的优雅解决方案。我似乎必须阅读一些关于泛型的内容。
【解决方案2】:

您可以在派生类上重新定义 Path 属性。 LinePath 可以有:

public new List<LineSegment> Segments 
{
    get
    {
        return (List<LineSegment>)base.Segments;
    }
}

这样您将强制使用正确的类型。

【讨论】:

  • 您希望避免定义“新”方法和属性签名,因为它们与多态性不兼容。
  • 我猜这是一个更简单(不使用泛型)的解决方案?
  • @Trevor:我不明白为什么它们与多态性不兼容。你能再开发一点吗?
  • @SoMoS 这应该比我在评论中更容易解释akadia.com/services/dotnet_polymorphism.html
  • 沿着通用路线走下去......大约是我学会如何使用它们的时候了。不是 100% 清楚的一件事是为什么将成员定义为接口列表而不仅仅是列表(IList 而不是 List)。
【解决方案3】:

当您的基类应提供某些方法的默认实现而其他方法应开放以被子类覆盖时,请使用抽象类。

例如再次以上面的 Vehicle 类为例。如果我们希望从 Vehicle 派生的所有类都以固定方式实现 Drive() 方法,而其他方法可以被子类覆盖。在这种情况下,我们将 Vehicle 类实现为具有 Drive 实现的抽象类,而将其他方法/属性保留为抽象类,以便它们可以被子类覆盖。

–> 抽象类的目的是提供一个基类的通用定义,多个派生类可以共享。

例如,类库可以定义一个抽象类,用作其许多函数的参数,并要求使用该库的程序员通过创建派生类来提供他们自己的类实现。

使用抽象类

When creating a class library which will be widely distributed or reused—especially to clients, use an abstract class in preference to an interface; because, it simplifies versioning. This is the practice used by the Microsoft team which developed the Base Class Library. ( COM was designed around interfaces.)

Use an abstract class to define a common base class for a family of types.

Use an abstract class to provide default behavior.

Subclass only a base class in a hierarchy to which the class logically belongs.

【讨论】:

    猜你喜欢
    • 2011-07-13
    • 2013-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-01
    • 2018-05-22
    • 2011-06-12
    相关资源
    最近更新 更多