4
class A
{
    public int x { get; set; }
    // other properties
}

class S
{
    public A GetA(...);
}

I would like to make the following restriction:
A can be only modified inside S. When someone else get A via GetA(), he can only get A's properties, not modify them.

I decided to make a new function in S that returns another object:

class B
{
    A a;
    public int x { get { return a.x; } }
    // replicate other A's properties
}

Is there a better solution?

Aage
  • 5,932
  • 2
  • 32
  • 57
Ivan
  • 57
  • 6

5 Answers5

7

You could make an interface of A with only the getters defined, and return that from GetA:

public interface IA
{
   int x { get; }
}

class A : IA
{
    public int x { get; set; } // nothing stopping you having a setter on the class
}

class S
{
    private A a = new A(); // you can call the setter internally on this instance
    public IA GetA(){ return a; } // when someone gets this thy only get the getter
}

Of course, there's nothing stopping someone casting the result of GetA to A and then they have the setter - but there's really nothing you can do about that!

Jamiec
  • 133,658
  • 13
  • 134
  • 193
  • 1
    I think one of his requirement is that *A can be only modified inside S*. But now `A` can be modified everywhere, if someone manages to get it. It's all about making it difficult for end user, may be nesting `A` is better here. – nawfal Nov 26 '13 at 09:54
  • Thank you for the comment. Actually i needed A to be modified inside a namespace that S is in, so i decided to use private A – Ivan Nov 26 '13 at 10:30
1

Perhaps a nested class could also meet your needs?

public class S
{
    private A ClassA { get; set; }

    public S()
    {
        ClassA = new A();
    }

    private class A
    {
        public int TestProperty { get; set; }
    }

    public int GetClassATestProperty
    {
        get
        {
            return this.ClassA.TestProperty;
        }
    }
}
Cloud9999Strife
  • 3,102
  • 3
  • 30
  • 43
1

You're kind of after friend keyword like in C++. And there is no equivalent in C# sadly.. I see some possibilities.

  1. Is S a kind of A? In that case inheritance can help you as you can restrict via protected modifier.

    class A
    {
        public int x { get; protected set; }
    }
    
    class S : A
    {
        public A GetA() { return this; } //or something like that.
    }
    
  2. Does A matter only to S? In that case you can make A a private inner class to S, as shown by Cloud9999Strife.

  3. Probably the best would be to leave A as an abstract class or interface for the public and have a concrete implementation of it nested in S - a combination of both Jamiec's and Cloud9999Strife's answer.

    public abstract class A // or interface
    {
       public abstract int x { get; }
    }
    
    class S
    {
        public A GetA() { return AImplInstead(); }
    
        class AImpl : A
        {
            // nothing stopping you having a setter on the class
            public override int x { get; set; } 
        }
    }
    

In essence, if A can be modified by one generic class, then it can be everywhere, unless there is a relation between A and S. That's how C# is designed. Now all we can do is make it (ie modifying A) difficult for end user. Exposing interface is one part of it. Nesting makes it one level deeper. Mind you, there is also reflection which will break all the encapsulation anyway..

Community
  • 1
  • 1
nawfal
  • 70,104
  • 56
  • 326
  • 368
0

You could change your implementation of A so that you introduce a readonly mode. After creating the instance, you can set the properties as you need. Once anyone gets the instance, you can enable the readonly mode. In readonly mode, the setters should throw an Exception, e.g. InvalidOperationException. In order to avoid a ton of if (IsReadOnly) ...; statements, you could use the Strategy pattern to change the behavior of the instance.
Depending on your needs, you can also create a copy with ReadOnly mode activated once a caller requests the object. This would allow for changes even after the instance was requested the first time.
An advantage of this over an interface is that a caller cannot use a cast to gain access to the setters. Though you do not have to implement an interface, the implementation of the readonly mode should be worth the effort. This depends on your analysis of risk and damage.

Markus
  • 20,838
  • 4
  • 31
  • 55
-1

Another option is to return a copy of A, not A itself.

class S
{
    public A GetA() { return a.Clone(); }
}

You could also make A a struct, which would cause this to happen automatically. This of course depends how big or complex A is. In most cases an interface might be better, as detailed in Jamiec's answer.

Rotem
  • 21,452
  • 6
  • 62
  • 109
  • 2
    I didnt downvote, but I think you misread the question :) The crucial part you missed "When someone else get A via GetA(), he can only get A's properties, not modify them" - cloning A does not fulfil this requirement – Jamiec Nov 26 '13 at 09:21
  • @Jamiec It does, in the sense that any properties he modifies on `A` are not propagated to the `A` found in `S`, which is what the OP wants to enforce. If `A` is a class which only contains two `int`s (think `Point`), I'd rather clone it and return that rather than return an interface. – Rotem Nov 26 '13 at 09:30
  • @Rotem I upvoted to cancel the downvote. I think your answer make sense as an *alternative*. But you should make the case clear in your answer. But I do think OP is needs more control on what the client *could* do with `A` class instances, to make the intent clear. For instance, what if `A` has `anotherProperty` which should be settable everywhere but not `x` property? Your solution can modify only a copy.. – nawfal Nov 27 '13 at 19:58
  • 1
    @nawfal I agree it would only make sense in a subset of possible cases, though in those cases, I personally would prefer it to an interface. We would have to know more about `A` in order to make a decision. – Rotem Nov 27 '13 at 22:02