簡體   English   中英

c#struct vs tuple中的值語義

[英]Value semantics in c# struct vs tuple

所以我在C#中邁出了第一步,正在制作一個簡單的瓷磚拼圖。 當我模擬瓷磚的位置時,我想要有價值語義。 因此,據我所知,基本上有兩種方法可以實現這一點,包括結構或元組。

在Tuple的情況下,我的代碼如下所示:

 public class TilePosition : Tuple<int,int> { public int HComponent{get { return Item1; }} public int VComponent{get { return Item2; }} public TilePosition(int horizontalPosition, int verticalPosition) : base(horizontalPosition, verticalPosition) { } } 

struct解決方案看起來像這樣:

 public struct TilePosition { private readonly int hComponent; private readonly int vComponent; public int HComponent { get { return hComponent; } } public int VComponent { get { return vComponent; } } public TilePosition(int hComponent, int vComponent) { this.hComponent = hComponent; this.vComponent = vComponent; } public static bool operator ==(TilePosition position1, TilePosition position2) { return position1.Equals(position2); } public static bool operator !=(TilePosition position1, TilePosition position2) { return !(position1 == position2); } } 

元組是簡潔的,但它暴露了Item1Item2 ,這會在公共API中混淆,即使我已經在它們周圍添加了H和V組件屬性。

結構需要更多的代碼,我得到一個編譯器警告我應該如何重寫Equals和GetHashCode,因為我重寫==!= ,但如果我這樣做,我沒有從使用結構(從語義和句法觀點)因為它與傳統的類完全相同。

除了沒有Item屬性的噪聲之外,在子類化元組上使用struc還有什么好處嗎?

我的解決方案是否都會以我預期的方式運行,或者我應該注意哪些細微差別?

IEquatable<TilePosition>在兩種情況下都可以實現IEquatable<TilePosition> - 特別是在結構案例中,以避免裝箱。)

除了沒有Item屬性的噪聲之外,在子類化元組上使用struc還有什么好處嗎?

鑒於它是不可變的,在這兩種情況下,你在兩種情況下都有大致“價值語義”,但仍然存在差異......

  • 類類型的實例需要堆上的空間(假設CLR沒有逃逸檢測等); 的結構類型的值可以在某些情況下僅使用堆棧
  • 傳遞類類型的值只意味着傳遞一個引用(4個字節或8個字節,具體取決於CLR架構); 傳遞struct類型的值確實傳遞了值(所以8個字節)
  • 在類類型中, null是一個有效值; 在結構類型版本中你需要使用TilePosition? 表示可能缺席的值
  • 在struct版本中, new TilePosition()是有效的,並且兩個字段的值都為0(這將是默認值,例如對於字段和數組元素)
  • 由於你沒有密封你的課程,有人可以創建一個可變的子類; 因此,它不是安全,為客戶以為這是完全不可改變的。 (你應該密封它......)
  • 您可以將您的類類型與任何使用Tuple<,>代碼一起使用,而結構類型顯然不是這種情況。
  • ==的含義在兩種類型之間會有所不同。 即使你在類類型中重載== ,調用者仍然可能只是比較引用。 在結構案例中,您仍然可以最終比較盒裝引用,無益。

當然,這些只是差異 - 它們是否算作一種方法的好處 ,另一種取決於您的要求。

如何使用鋸齒狀數組並在每個字段上持有一個項目。 這將更緊密地遵循瓷磚拼圖:

  • 它們的平鋪和空間是1:1的映射。 因此每個圖塊/空間只能有一個空格/圖塊。
  • 無需比較磁貼組件。
  • 移動瓷磚很容易,例如

      if (fields[x, y] = null) { fields[x, y] = fields[oldX, oldY]; fields[oldX, oldY] = null; } 

你最好的辦法就是把它做好並投入所有的工作。 如果你想要一個結構而不是一個類(可能適合你),這里有一個示例實現:

public struct TilePosition: IEquatable<TilePosition>
{
    public TilePosition(int horizontalPosition, int verticalPosition)
    {
        _x = horizontalPosition;
        _y = verticalPosition;
    }

    public int HComponent
    {
        get
        {
            return _x;
        }
    }

    public int VComponent
    {
        get
        {
            return _y;
        }
    }

    public static bool operator == (TilePosition lhs, TilePosition rhs)
    {
        return lhs.Equals(rhs);
    }

    public static bool operator != (TilePosition lhs, TilePosition rhs)
    {
        return !lhs.Equals(rhs);
    }

    public bool Equals(TilePosition other)
    {
        return (_x == other._x) && (_y == other._y);
    }

    public override bool Equals(object obj)
    {
        return obj is TilePosition && Equals((TilePosition)obj);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            return (_x*397) ^ _y;
        }
    }

    private readonly int _x;
    private readonly int _y;
}

暫無
暫無

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

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