1

I have a C# class with a field that needs to be visible from outside the class, but should be changed only from within the class. However, the problem is that the field is updated via a public mutator method, not directly (or by a property):

public class FirstClass
{
    public SecondClass TheField {get; private set;}

    public FirstClass()
    {
        TheField = new SecondClass();
    }

    public void SomeMethod()
    {
        // ...
        TheField.Update(/*parameters*/);
        // ...
    }
}

public class SecondClass
{
    // some fields  

    public SecondClass() { }

    public void Update(/*parameters*/)
    {       
        // do something
    }
}

In other words, I would like the method Update() to be accessible only from within FirstClass.

Few possible solutions and the reasons why I'm not safisfied with them:

  1. Change SecondClass with a setter instead of a method. - Wouldn't work because I need to have parameters and a lot of stuff to do.
  2. Make Update() internal instead of public. - Still accessible from within the assembly, not good enough.
  3. Modify SecondClass from the FirstClass, ie. move the method Update() to FirstClass, make it private and expose all needed fields from SecondClass. - doesn't feel very object-oriented.
  4. Call Update() from SecondClass constuctor(s) and make a new instance of SecondClass every time I need to update it. - The performance will suffer because there is some stuff in SecondClass that never changes and I would want to process it every time I call Update().

Is there a way to do this?

Tonci
  • 471
  • 2
  • 8

5 Answers5

4

A basic implementation of @aquaraga's answer, but using interfaces instead:

public interface ISecond
{
    // some properties  
}

public class FirstClass
{
    private readonly SecondClass _TheField;
    public ISecond TheField { get { return _TheField; } }

    public FirstClass()
    {
        _TheField = new SecondClass();
    }

    public void SomeMethod()
    {
        // ...
        _TheField.Update(/*parameters*/);
        // ...
    }

    private class SecondClass : ISecond
    {
        // some properties  

        public void Update(/*parameters*/)
        {       
            // do something
        }
    }
}

Essentially, expose a public interface that has all the accessible members but no Update method. Employ a private nested class which has an Update method, but otherwise not accessible to calling code and expose it as the interface, not as the class.

Some sample usage:

FirstClass myFirst = ...
myFirst.SomeMethod(); //updates ok!
Console.WriteLine(myFirst.TheField.PropertyA); //can access properties of ISecond
myFirst.TheField.Update(); //compiler error!

One point is that you mention using "some fields"; as an interface you wouldn't be able to have fields but properties instead. I'm not sure if that's a deal breaker or not for you.

EDIT: You mentioned your intent to reuse the SecondClass and minimize code duplication. One quick fix might be to declare some abstract class, a protected Update method, employ an internal constructor (so other assemblies can't inherit from it), then expose the Update call with a minimal implementation:

public abstract class SecondClassBase : ISecond
{
    // some properties

    internal SecondClassBase()
    {

    }

    protected void Update(/*parameters*/)
    {
        // do something
    }
}

Then in your FirstClass, nothing changes except the nested class:

public class FirstClass
{
    private readonly SecondClass _TheField;
    public ISecond TheField { get { return _TheField; } }

    public FirstClass()
    {
        _TheField = new SecondClass();
    }

    public void SomeMethod()
    {
        // ...
        _TheField.Update(/*parameters*/);
        // ...
    }

    private class SecondClass : SecondClassBase
    {
        public new void Update(/*parameters*/)
        {       
            base.Update(/*parameters*/);
        }
    }
}

Still some code duplication, but all you need to do now is copy/paste the code; no need to redeclare the properties or the Update logic for each implementation of FirstClass. You could also rename the new Update method to something else to avoid method hiding, but I figured I'd keep the same calling signature you had before.

Chris Sinclair
  • 22,858
  • 3
  • 52
  • 93
  • @ChrisSinclair: Great, this edited version of you answer is pretty much what I was looking for. Thanks! – Tonci Jun 07 '13 at 13:19
  • @Tonci Glad it'll work out for you! BTW, I just realized the constructor call was superfluous so all you really need is the `Update` method. – Chris Sinclair Jun 07 '13 at 13:21
1

One way is to make a sub-class called UpdateableSecondClass an inner class to FirstClass. It would inherit from SecondClass, and have a single method: Update()

Your SecondClass should not have the Update() method at all. You could continue exposing it to the rest of the world:

public SecondClass TheField {get; private set;}
aquaraga
  • 4,138
  • 23
  • 29
  • @aquarqa: With SecondClass : SecondClassBase? The reason why I don't like this solution is because I won't be able to reuse SecondClass - I would have to write that Update method many times... – Tonci Jun 07 '13 at 12:59
  • @Tonci is your intent to _reuse_ your `SecondClass` implementation across several different `FirstClass` classes? – Chris Sinclair Jun 07 '13 at 13:02
  • @ChrisSinclair, yes. I also have ThirdClass that also has a field of the type SecondClass. – Tonci Jun 07 '13 at 13:05
  • @Tonci, in the question, you mentioned that 'Update' method need to be accessed only by FirstClass. I'll edit my answer to clear up the confusion. – aquaraga Jun 07 '13 at 13:06
  • Sorry, I meant that the Update method needs to be accessed only by the class that holds that field. But I'm gonna need to have fields of the type SecondClass in more then one class. – Tonci Jun 07 '13 at 13:08
  • @Tonci: I've updated my answer with a method to minimize code duplication but still have the `Update` call only accessible to the wrapping class. – Chris Sinclair Jun 07 '13 at 13:13
1

I think that you can use this pattern:

public partial class FirstClass {
    partial class ThirdClass: SecondClass {
        public void PerformUpdate(/* parameters */) {
            base.Update(/* parameters */);
        }
    }

    public void SomeMethod() {
    }

    public FirstClass() {
    }

    public SecondClass TheProperty {
        get {
            return m_TheField;
        }
    }

    ThirdClass m_TheField=new ThirdClass();
}

public partial class SecondClass {
    protected void Update(/* parameters */) {
    }

    public SecondClass() {
    }
}

The ThirdClass inherits from SecondClass, but is not exposed. The property exposed as an instance of type SecondClass, but in fact a field of type ThirdClass.

The method SecondClass.Update exposes to derived class only. That you can declare SecondClass public, not nested, but keep the updating of filed private.

Ken Kin
  • 4,503
  • 3
  • 38
  • 76
0

What about a Nested Type.

public class FirstClass
    {
        private SecondClass TheField { get; set; }

        public void SomeMethod()
        {
            TheField.Update( /*parameters*/);
        }

        private class SecondClass
        {
            public void Update( /*parameters*/)
            {
                // do something
            }
        }
    }
S.N
  • 4,910
  • 5
  • 31
  • 51
  • My understanding is that `SecondClass` should still be accessible to outside code, just not updateable. – Chris Sinclair Jun 07 '13 at 12:46
  • @ChrisSinclair, If i get it correct, the question was more to do with how to expose the Method out and not about class. Anyways, thanks for the comment. – S.N Jun 07 '13 at 12:50
  • @Nair, Chris Sinclair is right, SecondClass should be accessible to outside code. TheField must have a public getter. – Tonci Jun 07 '13 at 12:51
0

Chris Sinclair answer is great,this is just another option

public sealed class FirstClass : SecondClass
{
    public FirstClass()
    {

    }

    public void SomeMethod(int j)
    {
        base.Update(j);
    }
}

public abstract class SecondClass
{

    public SecondClass() { }

    protected void Update(int i)
    {
        Console.WriteLine(i.ToString());
    }
}

this is just for the part of accessing the method through FirstClass

terrybozzio
  • 4,424
  • 1
  • 19
  • 25