如何在C#中为类中的结构提供不同的保护级别?

时间:2013-02-01 15:48:18

标签: c# oop class struct

我有一个包含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内的属性结构。

我怎么能做这样的事情?它甚至可能吗?

4 个答案:

答案 0 :(得分:3)

您可以将结构设置为只读以保持对值的控制。这是.NET部分中使用的模式:

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

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

然后你可以像以前一样创建你的属性,知道结构中的值将保持不变,除非你通过属性设置器。

答案 1 :(得分:2)

只需使用受保护的setter创建结构类型的属性:

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

Struct是一种值类型,因此客户端无法从MyClass更改项目的Data1Data2属性(客户端将具有项目的副本)。对于受保护的setter,只有MyClass及其继承者可以为item设置新值。如果您希望更新某个项目的项目数据,请使用class代替struct

答案 2 :(得分:0)

您应该阅读有关struct的更多内容 - 它应该是不可变的,这意味着您无法更改Item的属性,无论是来自MyClass或其他任何地方。

如果你看Stan Petrovs answer,你可以看到应该如何制作结构。

您的MyClass应该有类似的内容:

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

答案 3 :(得分:0)

构造中只有两种方式:

someThing.someMember.nestedMember = someValue;

可以是合法的:要么someMember返回对类实例的引用,在这种情况下,someThing的参与将在返回引用后立即停止,否则someThing.someMember必须是一个班级someThing的领域。它曾经在C#中是合法的,即使someMember返回了一个结构,以允许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属性也会起作用。不幸的是,即使在少数几种情况下,在只读结构值上调用属性setter会有所帮助(ArraySegment会提供另一个这样的例子)但是还没有定义任何属性可以告诉编译器何时这样一件事应该或不应该是允许的。

回到你现在的情景,我建议如果你的类型或衍生类型有可能希望改变一件物品而不改变两者,你最好的选择可能是声明一个开放式的结构您的复合项目类型,并包含在该类型的protected个字段中,以及返回它们的公共属性。这样做会允许派生类说:

item1.Data1 = whatever;

虽然外部代码必须使用Item1属性,即使Data1Item类型的公开可写字段,也可以尝试说:

item1.Data1 = whatever;

不会编译[请注意,如果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;
   }
 }

我个人不会真正看到添加额外的包装层的任何价值,但它可能有助于安抚“公共可变结构是邪恶的”人群。