Jon
Jon

Reputation: 15200

C# return a variable as read only from get; set;

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

Upvotes: 36

Views: 25813

Answers (7)

cdie
cdie

Reputation: 4544

I have faced this problem in a certain way. I have a CategoryViewModel class, which have a property Category that I want private read-only :

public CategoryViewModel
{
    private Category { get; }

}

In fact, I want it to be exported as read-only to other class. However I can't do such thing. In my case (maybe it will help some other guys), I want to add it to a repository. The only way that I've found is to have a function with the repository as param 1, and an Action as param 2 :

public void ApplyAction(ICategoryRepository repo, Action<ICategoryRepository, Category> action)
{
    action(repo, Category);
}

Like that, from elsewhere, I can do such thing :

 categoryViewModel.ApplyAction(_repository, (r, c) => r.MarkForInsertOrUpdate(c));

This can help other to expose there property only for certains cases and can manage them.

Upvotes: 0

Matt
Matt

Reputation: 3677

Your question reads like you're looking for:

public PropertyName { get; private set; }

But then, given the answers so far I'm not sure I'm interpreting your question correctly. Besides, who am I to question Jon Skeet? :)

Upvotes: 2

pingsft
pingsft

Reputation: 326

i agree with ReadOnlyCollection

See my simple code:

 private List<Device> _devices;
public readonly System.Collections.ObjectModel.ReadOnlyCollection<Device> Devices 
{
 get
 { 
return (_devices.AsReadOnly());
 } 

}

ReadOnlyCollection dosen't has Add method so user cant add properties to it.BUT ther is no warranty that if user can modify objects by calling their methods....

Upvotes: 0

justlost
justlost

Reputation: 193

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 =) )

Upvotes: 4

Jon Skeet
Jon Skeet

Reputation: 1500893

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 :)

Upvotes: 54

Jamie Ide
Jamie Ide

Reputation: 49261

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.

Upvotes: 3

Anton Gogolev
Anton Gogolev

Reputation: 115779

Return a reference to a stripped-down interface:

 interface IFoo
   string Bar { get; }

 class ClassWithGet
   public IFoo GetFoo(...);

Upvotes: 6

Related Questions