views:

186

answers:

6

I have three classes; Classes A and B both reference class C.

How can I make it so members of class C can be modified when referenced from class A but not modified when referenced from class B?

IE, the following should be possible;

classA myClassA = new classA();
myClassA.myClassC.IssueNumber = 3;

But this should not be possible;

classB myClassB = new classB();
myClassB.myClassC.IssueNumber = 3;

Making classB.classC read-only still allows properties of classC to be altered.

I'm sure this is basic stuff but can't find a simple answer.

Thanks, A

+3  A: 

You can't do it in C# as you would in C++. But you may define a readonly interface for class C that would be handled by B whereas A will handle the actual C.

Seb
+2  A: 

You can't assign rights as such to specific classes. However, you can place Class A and Class C in the same assembly and Class B in another. Then define the set accessor for the property as internal. This means that it can only be set by classes in the same assembly:

public int IssueNumber
{
  get;
  internal set;
}

Alternatively, you could implement a method on Class A which sets the property value, but not on class B:

public void SetIssueNumber(int value)
{
  this.myClassA.IssueNumber = value;
}
Bernhof
+3  A: 

I suggest you to split class C to 2 classes:

class C
{
    protected int _IssueNumber;

    public int GetIssueNumber()
    {
        return _IssueNumber;
    }
}

class WritableC : C
{
    public void SetIssueNumber(int issueNumber)
    {
        _IssueNumber = issueNumber;
    }
}

class A
{
    public WritableC myClassC;
    ...
}

class B
{
    public C myClassC;
    ...
}

EDIT:

As Martinho Fernandes said you can also use one class with 2 different interfaces:

interface IC
{
    int IssueNumber { get; }
}

interface IWritableC : IC
{
    int IssueNumber { get; set; }
}

class C : IWritableC
{
    protected int _IssueNumber;

    public IssueNumber
    {
        get { return _IssueNumber; }
        set { _IssueNumber = value; }
    }
}

class A
{
    public IWritableC myClassC;
    ...
}

class B
{
    public IC myClassC;
    ...
}
bniwredyc
Another option is to keep a single C class, but with an explicitly implemented interface that exposes the setter.
Martinho Fernandes
+14  A: 

Pattern 1: Make a simple read-only interface IRead. Make a simple write interface IWrite. Make an read-write interface IReadWrite : IRead, IWrite. Implement classC : IReadWrite. Declare myClassA.myClassC as IReadWrite. Declare myClassB.myClassC as IRead. (You don't have to user IWrite anywhere if you don't need it :-))

Pattern 2: create a read-only wrapper for classC called ReadOnlyClassC and use that one in classB.

Pattern 1 is used by the IO streams to split the reader and writer implementations and then combine them in read-write streams.

Pattern 2 is used by the generic collections to provide read-only facet.

Franci Penov
+1 for Pattern 1
chriszero
this is good stuff.
Bernhof
+1 for telling where the patterns are used in the BCL.
OregonGhost
+1  A: 

have a boolean isReadOnly in ClassC. Set this boolean using a constructor. While creating instance of ClassC in ClassB call ClassC myClassC = new ClassC(true); In the set block of IssueNumber, check for the boolean value. If true alter the value

bool isReadOnly;
public ClassC(bool isReadOnly)
{
    this.isReadOnly = isReadOnly;
}

int _issueNumber;
public int IssueNumber
{
    get
    {
        return _issueNumber;
    }
    set
    {
        if(!isReadOnly)
        {
            _issueNumber = value;
        }
    }
}
Veer
+1  A: 

If it is that important to make this difference, make an interface:

// read only interface
interface IC
{
  int IssueNumber { get; }
}

class C : IC
{
  int IssueNumber { get; set; }
}

// get the full type from A
class A
{
  C MyClassC { get; }
}

// only get read only interface from B
class B
{
  IC MyClassC { get; }
}
Stefan Steinegger