0

我正在試圖找到如何將功能添加到C#結構中,並且以比將它們包裝在全新類中更優雅的方式。擴展方法不如覆蓋強大,並且絕對不能提供結構事件觸發/處理功能。爲C#結構添加功能

我目前面臨的具體問題是檢測並對Vector2結構成員中的更改作出反應。這只是一個內部要求,所以我的圖書館的用戶應該能夠在與其交互時使用/感知Vector2結構(同時仍然引發內部事件)。


一般來說,我可以如何擴展C#的結構以外由擴展方法或封裝?

具體來說,我該如何擴展Vector2結構以支持事件觸發/處理?

+14

我會說你需要一個類,而不是一個結構 – devundef

+1

就像devundef說。 C#中的結構只不過是將相關數據放在一起的輕量級方式。如果你需要更多的邏輯和可擴展性,然後使用類。 – Euphoric

+0

@Euphoric:你爲什麼說C#中的結構是「僅僅是保持相關數據在一起的輕量級方式」?確實,一個結構不能繼承另一個結構,但是你可以在結構上有方法。你爲什麼說他們是「輕量級」? –

回答

2

一般情況下,如何擴展C#結構而不是擴展 方法或封裝?

唯一的方法是創建擴展方法或使用封裝。

具體來說,我該如何擴展Vector2結構來支持事件 射擊/處理?

正如我前面所說,你可以使用封裝和創建一個類。所以使用這個代碼:

public class ExtendedVector2 { 
    public Vector2 Vector{ 
     get; 
     private set; 
    } 

    public ExtendedVector2(float value){ 
     Vector = new Vector2(value); 
    } 

    public ExtendedVector2(float x, float y){ 
     Vector = new Vector2(x, y); 
    } 
} 

然後你可以添加接口,方法和事件。

編輯:

但我將如何檢測是否X或Y的變化?假設用戶「獲取」矢量,然後設置其中一個成員(X或Y)。我可以添加事件 當Vector設置爲整體時觸發,但不是當其中一個 成員設置在'get'後面時。請記住,我不想強​​制 用戶使用新的矢量類以便與我的 庫進行交互。我甚至不希望他/她必須知道內部使用了一個新的矢量類 。

首先,如果你想使用類型的結構Vector2你應該重寫以這種方式的所有方法完全在內部面膜:

public class ExtendedVector2 { 
    //... 
    private Vector2 _vector2; 

    //mask X and Y values of Vector2 structure 
    public float X{ 
     set{ _vector2.X = value; } 
     get{ return _vector2.X; } 
    } 

    public float Y{ 
     set{ _vector2.Y = value; } 
     get{ return _vector2.Y; } 
    } 

    //example to mask a method of Vector2 structure 
    public static float Dot(ExtendedVector2 value1, ExtendedVector2 value2){ 
     return Vector.Dot(value1, value2); 
    } 

    //override the cast to Vector2 
    public static implicit operator Vector2(ExtendedVector2 value) //I'd make it implicit because I'd think to it like an upcast 
    { 
     return new Vector2(value.X, value.Y); 
    } 
} 

欲瞭解更多信息look here

現在很簡單,如果你想創建一個成員更改時觸發的事件。 我會創建一個costumized的EventArgs。讓我們來編寫一些代碼:

//use the convention of eventName+EventArgs 
class MemberChangedEventArgs : EventArgs 
{ 
    public readonly float LastValue{ 
     get; 
     set; 
    } 
    public readonly float NewValue{ 
     get; 
     set; 
    } 

    public MemberChangedEventArgs(float LastValue, float NewValue) 
    { 
     this.LastValue = LastValue; 
     this.NewValue = NewValue; 
    } 
} 

然後你可以編寫自己的事件:

public class ExtendedVector2 { 
    private Vector2 _vector2; 

    public float X{ 
     set{     
      if(_vector2.X != value)   
       OnMemberXChanged(new MemberChangedEventArgs(_vector2.X, value)); 

      _vector2.X = value; 
     } 
     get{ return _vector2.X; } 
    } 

    public float Y{ 
     set{ 
      if(_vector2.Y != value) 
       OnMemberYChanged(new MemberChangedEventArgs(_vector2.Y, value)); 

      _vector2.Y = value;      
     } 
     get{ return _vector2.Y; } 
    }   

    public event EventHandler<MemberChangedEventArgs> MemberXChanged; 
    public event EventHandler<MemberChangedEventArgs> MemberYChanged; 

    public ExtendedVector2(float value){ 
     Vector = new Vector2(value); 
    } 

    public ExtendedVector2(float x, float y){ 
     Vector = new Vector2(x, y); 
    } 

    private virtual void OnMemberXChanged(MemberChangedEventArgs e){ 
     if(MemberXChanged != null) 
      MemberXChanged(this, e); 
    } 

    private virtual void OnMemberYChanged(MemberChangedEventArgs e){ 
     if(MemberYChanged != null) 
      MemberYChanged(this, e); 
    } 
    //... 

    //here mask the Vector2 structure using the previous solution 
} 
+0

但是,我會如何檢測X或Y是否發生了變化?假設用戶「獲取」Vector,然後設置其中一個成員(X或Y)。我可以在Vector的整體設置時添加事件觸發,但不能在「get」之後設置其中的一個成員。請記住,我不想強​​制用戶使用新的矢量類來與我的庫進行交互。我甚至不希望他/她必須知道內部使用了一個新的矢量類。 – Griffin

+0

好的,我編輯了我的答案。 –

+1

我的編輯能幫助你嗎? –