views:

1086

answers:

4

Hi all,

I swear I have seen an example of this but have been googling for a bit and can not find it.

I have a class that has a reference to an object and need to have a GET; method for it. My problem is that I do not want anyone to be able to fiddle with it, i.e. I want them to get a read only version of it, (note I need to be able to alter it from within my class).

Thanks

+3  A: 

Return a reference to a stripped-down interface:

 interface IFoo
   string Bar { get; }

 class ClassWithGet
   public IFoo GetFoo(...);
Anton Gogolev
Ideally including a `private` or `internal` implementation of IFoo so that it cannot be cast back ;)
jerryjvl
Hum no, if the Interface is internal or Private you won't be able to return a Public member that has a non accessible type. This won't compile : "Inconsistent accessibility: field type ... is less accessible than field ..."
Julien N
+28  A: 

No, there's no way of doing this. For instance, if you return a List<string> (and it's not immutable) then callers will be able to add entries.

The normal way round this is to return an immutable wrapper, e.g. ReadOnlyCollection<T>.

For other mutable types, you may need to clone the value before returning it.

Note that just returning an immutable interface view (e.g. returning IEnumerable<T> instead of List<T>) won't stop a caller from casting back to the mutable type and mutating.

EDIT: Note that apart from anything else, this kind of concern is one of the reasons why immutable types make it easier to reason about code :)

Jon Skeet
+1 for cloning (except I already +1'd)
Jon B
+3  A: 

This isn't possible. Get and set accessors to reference types get and set the reference to the object. You can prevent changes to the reference by using a private (or internal) setter, but you cannot prevent changes to the object itself if it's exposed by a getter.

Jamie Ide
+1  A: 

If the object isn't too complicated/extensive then write an wrapper around it.

for example:

class A {
    public string strField = 'string';
    public int intField = 10;
}

class AWrapper {
    private A _aObj;

    public AWrapper(A aobj) {
      _aObj = A;
    }

    public string strField {
         get {
            return _aObj.strField;
         }
    }

    public int intField {
         get {
            return _aObj.intField;
         }
    }
}

So now all you do is give your client code an instance of the AWrapper class so that they may only use what you allow them to see.

this may get a bit complicated and may not scale well if your base class is not set in stone, but for most simple situation it may just do the trick. I think this is called a facade pattern(but don't quote me on that =) )

justlost