views:

69

answers:

2

How to define a struct whose members can be accessed by any internal classes via properties but can only be set by a particular internal class? (If it is possible.)

If it is not possible, is there a work-about to achieve the similar requirement?

Edit 1: below

Reason:

I have a class A with two members _x and _arrB. _x can be read but not modified by internal classes (except class A) through x.

I also want to allow internal classes to read structB elements in _arrB and to read members of those structB. But I only want class A to be able to modify either a structB element in _arrB or a member of those structB. Hence I think I need a struct that can specify which internal classes can modify its member.[1]

class A 
{
    private int _x;
    internal int x
    {
        private set
        {
            _x = value / 2;
        }
        internal get
        {
            return _x * 2;
        }
    }

    private B[] _arrB;
    internal B[] arrB
    { 
        private set
        {
            _arrB = value;
        }
        internal get
        {
            return _arrB;
        }
    }

    public A() 
    {
        _x = //value read from somewhere;            

        //do something to determine size
        _arrB = new B[size];
        //populate _arrB
        ...
    }


}

Note: By internal class I mean a class in the same assembly, not a nested class.

[1] However, _arrB is an array, which is an object, which is a reference type. When an internal class gets a reference of _arrB, elements of structB may be modified without control. I realized that I do not want inner classes to set _arr[0] to null. So any solution have to take this into account.

I will think about it for the rest of the day and post a solution when I have thought of one.

+1  A: 

The only I can think of is to use the stack trace to get the calling frame, then the calling method, then the reflected type of that method. You can then check that type is what you are expecting.

EDIT, WARNING, BAD CODE:

StackTrace oStack = new StackTrace(true);

string callingType = oStack.GetFrame(1).GetMethod().ReflectedType.FullName;

if(callingType != "MyAcceptableClass")
    throw new MethodAccessException(
          callingType + " is not allowed to call this method");

I'd personally reconsider your design, maybe these classes shouldn't be in the same assembly? You could then make two assemblies friend assemblies so they can access eachother's internal members.

David Neale
Yup, I am reconsidering the design. I don't quite understand your solution though, given my current knowledge. But thanks anyway.
blizpasta
The above is what I was thinking, but I wouldn't suggest using it.
David Neale
+1  A: 

I wonder why you want to do that. Only ugly hacks are possible AFAIK.

BEGIN WARNING: do not read if you dislike ugly code!!!

What David Neale said.

You could put them in separate assemblies and set them to friendly:

[assembly:InternalsVisibleToAttribute("assembly name", "key")]

You could design the class like this:

internal struct ModifiedStruct
{
    public int Value {get; private set; }

    internal class ModifyingClass
    {
        public void ModifyValue()
        {
            ModifiedStruct s = new ModifiedStruct();
            s.Value = 456;
        }
    }

}

END WARNING

Edit (question changed) To prohibit modification of a collection, use the ReadOnlyCollection Class.

internal ReadOnlyCollection<B> BCollection
{
    get
    {
        return new ReadOnlyCollection<B>(_arrB);
    }
}
Jaroslav Jandek
Thank you for your suggestion of using a ReadOnlyCollection. With it I can implement a more elegant and readable solution.
blizpasta
typo: should be ReadOnlyCollection<B>, but I know what you mean.
blizpasta
@blizpasta: Typo fixed, thank you for noticing :)
Jaroslav Jandek