結構struct(值型別)在實際應用中應該注意的點

lee_lgw發表於2021-09-09

.Net中的資料型別大致可以分為二類:一類是值型別,一類是引用型別;結構(struct)是值型別,從效能上考慮值型別更有優勢(關於值型別與引用型別的詳細討論不在本文範圍內,大家可以去查閱相關資料).對於一些特定場合:比如僅需要儲存資料,不需要體現具體方法的時候,建議大家用struct來代替class,但在使用過程中,有幾個容易被忽視的細節.

1.使用struct儲存資料做為資料來源,與資料顯示控制元件繫結時:

程式碼如下:

Code
protected void Page_Load(object sender, EventArgs e)
        {
            List _list = new List();
            _list.Add(new MyStruct3() { Name = "abc", Value = "123" });
            _list.Add(new MyStruct3() { Name = "cde", Value = "345" });

            this.Repeater1.DataSource = _list;
            this.Repeater1.DataBind();
            
        }

 public struct MyStruct3
        {
            public string Name;
            public string Value;

        }

 

前端aspx關鍵程式碼:

圖片描述圖片描述Code

        
            
;
        

    

 

編譯時一切正常,但是執行後,報類似如下錯誤:

DataBinding:“Test._Default+MyStruct3”不包含名為“Name”的屬性

咋整?把MyStruct3的定義改成這樣:

Code
public struct MyStruct3
        {
            public string Name{set;get;}
            public string Value { set; get; }

        }


即:我們把欄位(Field)改成屬性(property),再次執行,一切OK (應該是跟採用反射機制有關)

2.結構的建構函式問題

看如下程式碼

圖片描述圖片描述Code
public struct MyStruct {
            private string _name;
            private string _value;

            public string Name {
                set { _name = value; }
                get { return _name; }
            }

            public string Value
            {
                set { _value = value; }
                get { return _value; }
            }

            public MyStruct(string pName, string pValue) 
            {
                _name = pName;
                _value = pValue;
            }
        }

 

一切跟在Class中寫的一樣,沒什麼特別的,但是我們改成下面的寫法:

圖片描述圖片描述圖片描述Code
public struct MyStruct
        {
            public string Name { set; get; }
            public string Value { set; get; }

            public MyStruct(string pName, string pValue) 
            {
                Name = pName;
                Value = pValue;               
            }
        }
圖片描述

即利用c#3.0的自動屬性,簡化了一下程式碼,這次編譯時vs卻提示有錯:
"錯誤 在控制返回到呼叫程式之前,自動實現的屬性“Test._Default.MyStruct2.Value”的支援欄位必須完全賦值。請考慮從建構函式初始值設定項中呼叫預設建構函式。 "
"在給“this”物件的所有欄位賦值之前,無法使用該物件"

究其原因,我們用Reflector看下編譯器是如何處理"自動屬性"的,先把結構改成普通的類(目的是讓編譯先透過,好觀察最終生成的程式碼

圖片描述圖片描述Code
 public class MyClass
        {
            public string Name{set;get;}
            public string Value { set; get; }

            public MyClass(string pName, string pValue) 
            {
                Name = pName;
                Value = pValue;
            }

        }

用Reflector反編譯成C# 1.0後,程式碼如下:

圖片描述圖片描述圖片描述Code
public class MyClass
{
    // Fields
    [CompilerGenerated]
    private string k__BackingField;
    [CompilerGenerated]
    private string k__BackingField;

    // Methods
    public MyClass(string pName, string pValue)
    {
        base..ctor();
        this.Name =
 pName;
        this.Value =
 pValue;
        return;
    }

    // Properties
    public string Name
    {
        [CompilerGenerated]
        get
        {
            string str;
            str = this.k__BackingField;
        Label_0009:
            return str;
        }
        [CompilerGenerated]
        set
        {
            this.k__BackingField = value;
            return;
        }
    }

    public string Value
    {
        [CompilerGenerated]
        get
        {
            string str;
            str = this.k__BackingField;
        Label_0009:
            return str;
        }
        [CompilerGenerated]
        set
        {
            this.k__BackingField = value;
            return;
        }
    }
}
圖片描述

 

觀察一下建構函式,變成了
...
base..ctor();
this.Name = pName;
...

關鍵就在這裡:對於類來講,並不要求在訪問類的例項之前對所有成員賦值,所以這裡引用this是合法的;而值型別要求在使用前必須對所有成員賦值,所以值型別如果在建構函式中直接給自動屬性賦值,這裡this代表的就是結構本身,而在此之前自動生成的二個私有成員private string k__BackingField和private string k__BackingField還沒賦值,因此報錯也就是合情合理了

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/1020/viewspace-2808425/,如需轉載,請註明出處,否則將追究法律責任。

相關文章