There are only two ways in which a construct like:
someThing.someMember.nestedMember = someValue;
can be legal: either someMember
return a reference to a class instance, in which case someThing
's involvement will cease as soon as the reference is returned, or else someThing.someMember
must be a field of class someThing
. It used to be legal in C# even if someMember
returned a struct, to allow for the possibility that someMember
might do something like:
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);} }
}
In this scenario, MemberProxy
doesn't actually hold the data for nestedMember
, but instead holds a reference to the actual place it's contained. Thus, even if an instance of MemberProxy
is not writable, an attempt to set its nestedMember
property would work. Unfortunately, even though there are a few cases where invoking a property setter on a read-only struct value would be helpful (ArraySegment
would provide another such example) there is as yet no attribute defined which would tell the compiler when such a thing should or should not be permissible.
Returning to your present scenario, I would suggest if there's any substantial likelihood that your type or a derived type may wish to alter one piece of an item without altering both, your best bet may be to declare an open-field structure of your composite-item type and include within your class protected
fields of that type, along with public properties which return them. Doing that would allow your derived classes to say:
item1.Data1 = whatever;
while outside code would have to use the Item1
property and even if Data1
is an exposed writable field of type Item
, an attempt to say:
item1.Data1 = whatever;
would not compile [note that even older compilers which would accept such a statement if Data1
were a read/write property, on the theory that it might be useful, would correctly reject it when Data1
is a field]. If you're determined not to expose a public mutable structure, you could always do something like:
public struct Item
{
privateItem Value;
public Type1 Data1 {get {return Value.Data1; }}
public Type1 Data2 {get {return Value.Data2; }}
Item(privateItem src)
{
Value = src;
}
}
I personally wouldn't really see any value in adding an extra layer of wrapping, but it might help appease the "public mutable structs are evil" crowd.