我有一个包含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
内的属性结构。
我怎么能做这样的事情?它甚至可能吗?
答案 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更改项目的Data1
或Data2
属性(客户端将具有项目的副本)。对于受保护的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
属性,即使Data1
是Item
类型的公开可写字段,也可以尝试说:
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;
}
}
我个人不会真正看到添加额外的包装层的任何价值,但它可能有助于安抚“公共可变结构是邪恶的”人群。