1
\$\begingroup\$

I wondered how nested classes in C# work as I often use them when I write native C# code (like Woods.Tree.Add(new Tree).Leaf.Color) so i tried it by my self with a Navigation example. There is a Position integer which declares a point on a line. To move left the position will be subtracted by 1, to move right the position will added by 1.

I think its quite pedantic and much code to write for such a 'simple' task. Is this the right way or is there an easier, smaller way to archive this?

using System;

namespace ConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {
            NestedTest nt = new NestedTest();//create test
            nt.Navigate.Left();
            Console.WriteLine(nt.Position);
            nt.Navigate.Left();
            nt.Navigate.Left();
            Console.WriteLine(nt.Position);
            nt.Navigate.Rigth();
            Console.WriteLine(nt.Position);
            Console.WriteLine("Press any key to exit...");
            Console.ReadKey();    
        }
    }
    class NestedTest
    {
        public int Position { get; private set; }
        public NavigateClass Navigate;//create the NavigateClass in NestedTest

        //Nested NavigateClass
        public class NavigateClass
        {
            private NestedTest _o;//the placeholder
            public NavigateClass(NestedTest obj)
            {
                _o = obj;//Set the NestedTest class so we know which Position we have to navigate trough.
            }
            public void Left()
            {
                Console.Write("<-");
                _o.Position--;//Move Position to the left (-1)
            }

            public void Rigth()
            {
                Console.Write("->");
                _o.Position++;//Move Position to the right (+1)
            }
        }

        public NestedTest(int num = 10)
        {
            this.Position = num;//Set start position
            Navigate = new NavigateClass(this);//Set the _o in Navigate so it knows which Position it has to navigate trough
        }
    }

}
\$\endgroup\$
0

1 Answer 1

5
\$\begingroup\$

Is this the right way or is there an easier, smaller way to archive this?

It depends on how you define the right way. Is your goal short and small code or is your goal testability and maintainability? These two goals are mutualy exclusive.


If you want to have it short then of course there is a way. You don't need the nested class at all.

class NestedTest
{
    public int Position { get; private set; }

    public void Left()
    {
        Console.Write("<-");
        Position--;
    }
}

If you want to have maintainable code then you need to write more code and correctly use dependency injection and possibly use a few interfaces as abstractions. Nested public classes are a bad style anyway so you should avoid them.

This is how such an implementation could look like. The NestedTest gets an interface that allows accesing its Position. Its constructor also requries a lambda that lets you specify the navigator for this instance.

public interface IPositionable
{
    int Position { get; set; }
}

class NestedTest : IPositionable
{
    public int Position { get; set; }

    public INavigator Navigator { get; }

    public NestedTest(int num, Func<IPositionable, INavigator> createNavigator)
    {
        Position = num;
        Navigator = createNavigator(this);
    }
}

Where the Navigator is now also abstracted by an interface and can be faked for testing or exachnged for another navigator later:

public interface INavigator
{
    void Left();
}

public class Navigator : INavigator
{
    private IPositionable _positionable;

    public Navigator(IPositionable positionable)
    {
        _positionable = positionable;
    }

    public void Left()
    {
        _positionable.Position--;
    }
}

It's up to you to decide. Shortest code possible or testable and maintainable?

\$\endgroup\$
2
  • \$\begingroup\$ Okay, so my idea was correct to pass the outer class to the inner class, and this is the way you do it in C#, right? Thanks for the example with the interfaces \$\endgroup\$
    – Max R.
    Commented Sep 7, 2017 at 15:06
  • \$\begingroup\$ @MaxR. yes, in general the idea was ok but using a nested class not so much. Usually it's better to use abstractions if you are going to extend or test it later. \$\endgroup\$
    – t3chb0t
    Commented Sep 8, 2017 at 16:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.