簡體   English   中英

如何在C#中的類內部為結構提供不同的保護級別?

[英]How can I have different protection levels for a struct inside a class in C#?

我有一個具有6個屬性的類,這些屬性基本上是3對屬性,每對包含有關一件事的數據。 所有這些屬性都是公開的,但是設置它們受到保護。 它顯示在下面的代碼中:

public class MyClass
{
    public Data1Type Item1Data1 { get; protected set; }
    public Data2Type Item1Data2 { get; protected set; }
    public Data1Type Item2Data1 { get; protected set; }
    public Data2Type Item2Data2 { get; protected set; }
    public Data1Type Item3Data1 { get; protected set; }
    public Data2Type Item3Data2 { get; protected set; }
}

因為每對屬性基本上都被視為一個項目,所以我決定制作一個結構如下:

struct Item
{
    Data1Type Data1;
    Data2Type Data2;
}

因此,我用一個Item結構替換了每對屬性。

我現在面臨的問題是,我找不到一種具有3對屬性的具有相同保護級別的方法。 我希望MyClass之外的所有內容都能夠獲取Item結構中的屬性,但只有MyClass和派生自其的類才能更改Item結構中的屬性。

我該怎么做? 可能嗎?

您可以將結構設為只讀,以保留對值的控制。 這是.NET部分中使用的模式:

struct MyStruct
{
    public readonly int Field1;
    public readonly int Field2;

    public MyStruct(int i, int j)
    {
        Field1 = i;
        Field2 = j;
    }
}

然后,您可以像以前一樣創建屬性,知道結構中的值將保持不變,除非您通過屬性設置器。

只需使用受保護的setter創建結構類型的屬性即可:

public class MyClass
{
    public Item Item1 { get; protected set; }
    public Item Item2 { get; protected set; }
    public Item Item3 { get; protected set; }
}

結構是一種值類型,因此客戶端無法從MyClass更改項目的Data1Data2屬性(客戶端將獲得項目的副本)。 使用受保護的設置器時,只有MyClass及其繼承者可以為item設置新值。 如果要更新某個項目的項目數據,請使用class而不是struct

您可能應該閱讀有關struct更多信息-它意味着是不可變的 ,這意味着無論從MyClass還是從其他任何地方,您都不能更改Item的屬性。

如果您查看Stan Petrovs的答案 ,您會看到應該如何構造結構。

然后,您的MyClass應該具有以下內容:

protected void SetItem1Data1(DataType1 newValue) 
{
    this.Item1 = new Item(newValue, this.Item1.Data2);
}

構造只有兩種方式:

someThing.someMember.nestedMember = someValue;

可能是合法的: someMember返回對類實例的引用,在這種情況下, someMember返回引用, someThing的參與就會停止,否則someThing.someMember必須是someThing類的someThing 即使someMember返回了一個結構,它在C#中也是合法的,以允許someMember可能執行以下操作:

public class Thing { ...
    private nestedType member_nestedMember;
    public struct MemberProxy {
        Thing _owner;
        internal MemberProxy(Thing owner) {_owner = owner;}
        nestedType nestedMember {
            get {return _owner.member_nestedMember;}
            set {_owner.member_nestedMember = value; }
        }
    }
    public MemberProxy someMember {get {return new MemberProxy(this);} }
}

在這種情況下, MemberProxy實際上並不保存nestedMember的數據,而是保留對它所包含的實際位置的引用。 因此,即使MemberProxy的實例不可寫,也可以嘗試設置其nestedMember屬性。 不幸的是,即使在某些情況下,在只讀結構值上調用屬性設置器會有所幫助( ArraySegment將提供另一個此類示例),但仍未定義任何屬性來告訴編譯器何時應該這樣做或應該是不允許的。

回到您目前的情況,我建議,如果您的類型或派生類型在很大程度上可能希望更改一項而不改變兩者,則最好的辦法是聲明復合材料的開放字段結構,項目類型,並在您的類的protected字段中包括該類型以及返回它們的公共屬性。 這樣做將允許您的派生類說:

item1.Data1 = whatever;

而外部代碼將必須使用Item1屬性,即使Data1Item類型的公開可寫字段,也嘗試說:

item1.Data1 = whatever;

不會編譯[請注意,即使Data1是一個讀/寫屬性,即使較舊的編譯器也可以接受這樣的語句, Data1理論上講它可能是有用的,當Data1是字段時,它也會正確拒絕它。 如果確定不公開公共可變結構,則可以始終執行以下操作:

public struct Item
{
   privateItem Value;
   public Type1 Data1 {get {return Value.Data1; }}
   public Type1 Data2 {get {return Value.Data2; }}
   Item(privateItem src)
   {
     Value = src;
   }
 }

我個人認為增加一個額外的包裝層沒有任何價值,但是它可能有助於安撫“公共可變結構是邪惡的”人群。

暫無
暫無

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

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