簡體   English   中英

在 C# 中用於驗證父構造函數中參數的派生類中定義常量值的正確方法是什么

[英]What is the correct way to define a constant value in a derived class used to validate parameters in a parent constructor in C#

在派生類中定義常量值以驗證父構造函數中的參數的正確方法是什么。

給出以下示例:

public abstract class Polygon
{
    protected abstract int VertexCount { get; }
    public LineSegment[] Edges { get { /* ... */ } }
    public Point2D[] Vertices { get { /* ... */ } }

    protected Polygon(Point2D vertices)
    {
        if(vertices.Length != VertexCount)
            threw new ArgumentOutOfRangeException(...);
    } 
}

public class Triangle: Polygon
{
    protected override int VertexCount { get; } = 3;
    public Triangle(Point2D[] vertices) : base(vertices){}
}

public class Quadrilateral: Polygon
{
    protected override int VertexCount { get; } = 4;
    public Quadrilateral(Point2D[] vertices) : base(vertices){}
}

顯然,由於Virtual member call in constructorVirtual member call in constructor上述內容沒有按預期工作(是的,我理解警告,我不是問這個)

在我的邏輯中(似乎有缺陷), VertexCountPolygon類的一個特性(因為EdgesVertices的數組的固定大小將由 Polygon 類在初始化期間定義),並根據派生類(因此需要在派生類中定義)。

派生類需要定義VertexCount的值,因為它特定於派生類,但是,基類不知道派生類。 這就是使用“抽象整數”的原因,以確保派生類覆蓋它。 此外, VertexCount是一個屬性,因為字段不能是抽象的。 然而,它也應該是一個常數(因為三角形的邊總是 3,而四邊形的邊總是 4)。

最后,在基本構造函數中拋出的Exception消息應該是這樣的:

if(vertices.Length != VertexCount)
    threw new ArgumentOutOfRangeException(nameof(vertices),
        message: $"A {this.ToString()} requires exactly {VertexCount} vertices, received {vertices.Length}");

當然,'this.ToString()' 部分將在基類而不是派生類的上下文中調用(也許反射解決方案可以在這里工作)?

因此,對於所有這些,替代方案是VertexCount基類中的構造函數,在派生類中為VertexCount創建一個常量,並在派生類構造函數中初始化和設置所有值。 這似乎是派生類中的大量重復代碼(可能不在上面的示例中,因為從技術上講,我只在每個類中復制 2 行代碼,但是當構造函數變重時會發生什么)。

使用最少的重復代碼執行此操作的“正確”方法是什么?

在重新閱讀 Peter Duniho 的評論后,我想出了這個重構,我認為這是一個更好的解決方案。 (我認為這個問題的措辭有點模棱兩可/主觀,因為最初的邏輯是錯誤的,我正在尋找對我的邏輯的更正,而不是確切地知道問題是什么以及如何解決該問題)

問題:

在 C# 中用於驗證父構造函數中參數的派生類中定義常量值的正確方法是什么

簡短的回答,你沒有。 不需要在上面的示例代碼中定義常量。 它根本不需要存儲,它不是代碼的其他部分(在這種情況下)需要的東西,它是一個僅在實例化時驗證所需的值。

public class Triangle: Polygon
{
    public Triangle(Point2D[] vertices) : base(vertices, 3){}
}

public class Quadrilateral: Polygon
{
    public Quadrilateral(Point2D[] vertices) : base(vertices, 4){}
}

我試圖完成的另一個目標(使用原始示例)是早期驗證。 換句話說,如果沒有為派生類型傳遞正確數量的頂點,我想在對無效對象執行任何其他初始化步驟之前停止初始化。 在給定的例子中,一個空的默認構造函數和派生構造函數中的驗證(甚至從派生構造函數調用包含在基方法中的驗證方法)就可以了,不將頂點傳遞給基,而是驗證然后在派生構造函數中設置它們。 然而,關鍵是早期驗證,如果基類在到達派生類之前做了一堆東西(一個更復雜的類)來(預)初始化對象呢? 驗證代碼真正屬於任何處理(包括初始化)之前。

通過將(與驗證相關的)值傳遞給基本構造函數,允許在開始時進行驗證,從而在驗證失敗時防止其他代碼運行。

protected Polygon(Point2D[] vertices, int expectedVerticesCount)
{
    // Don't bother initializing the object, the data is invalid!
    if(vertices.Length != expectedVerticesCount)
        throw new ArgumentOutOfRangeException( /* ... */);

    // The data is valid, proceed with initialization
    Vertices = vertices;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM