dif
dif

Reputation: 2493

Hierarchical structuring of Functions inside a Class (C#)

is it possible to structure functions inside a class, to make some functions only accessable through a prewritten identifier?

I'll try to make my question a litte more clear with a (poor) example ;-) My class car got the functions drive, openDoor, closeDoor, startEngine, etc. But, to keep it clear, i would like to acces these functions like this:

car.drive()
car.door.open()
car.door.close()
car.engine.start()

I tried with structs and nested classes, but i don't think those were the right ways, because i don't like to have to create an object for every "identifier" i use.

Are there any "clean" ways to do this?

Thanks!

Edit: I'm not sure if it matters but heres some additional information:

Upvotes: 2

Views: 256

Answers (4)

wilson0x4d
wilson0x4d

Reputation: 8749

Nested classes are not necessary here, for anyone having trouble understanding, the following is a nested class approach:

public class Car
{
    public static Car Instance { get; private set; }
    static Car() { Car.Instance = new Car(); }
    private Car() { }
    public static class Door
    {
        public static void Close()
        {
            /* do something with Car.Instance */
        } 
    }
}

The use of static classes yields the following syntax:

Car.Door.Close();

C# allows you to nest class definitions it does not have a formal concept of 'inner types' or 'inner classes' as other languages do.

This is an excellent example of poor component modeling/design.

Consider the following, which is a more acceptable and more elegant solution:

public interface ICar
{
    IDoor Door { get; set; } 
}

public class Car : ICar
{
    public IDoor Door { get; set; }
}

public interface IDoor
{
    void Open();
    void Close();
}

public class Door : IDoor
{
    public override void Open() { /* do something */ }
    public override void Close() { /* do something */ }
}

With the above could use C#'s initializer syntax:

var car = new Car
{
    Door = new Door()
};

car.Door.Open();

If your gripe is with constantly needing to type "new XYZ" you can also bake initialization into the constructor. Done properly with a 'poor man' DI pattern it should look like this:

public class Car : ICar
{
    public IDoor Door { get; set; }
    public Car()
        : this(new Door())
    {
    }
    public Car(IDoor door)
    {
        this.Door = door;
    }
}

This avoids the need to perform initialization as part of creation, and allows you to inject new/different Door types into the stack.

var common = new Car();
var lambo = new Car(new LamboDoor());

In either case, calling code looks the same:

common.Door.Open();
lambo.Door.Open();

Lastly, you could consider a Composition or DI framework rather than bake new() operators into your implementation code. In any case, the most appropriate approach is to use properties and construct a legitimate object model which expresses your intent. Nested types do not yield the syntax you're looking for unless static members are used and taking that approach is very rarely a good idea, I've only seen it for simplistic singleton implementations, certainly never for API/Framework/Model definition.

Upvotes: 1

Jesse Seger
Jesse Seger

Reputation: 960

Just my 2 sense.

I like @Code Gray idea of nested classes. But to achieve the correct order of calling the methods, I think you need to nest car under Driver. The Driver would do something like this.

public class Driver
{
   public void Drive(Car car)
   {
      car.drive();
      car.door.open();
      car.door.close();
      car.engine.start();
   }
}

Upvotes: 0

Cody Gray
Cody Gray

Reputation: 244732

Nested classes would be the correct approach.

Consider that all Door objects would have Open and Close methods, and a Car object would have several instances of the Door object (2, maybe 4, or even more).

Likewise, each Car object would have an instance of the Engine object, which can be Started, Stopped, and have the oil changed (ChangeOil).

Then, each of these classes would be extensible beyond the Car class. If you wanted to change some of the code inside of your Door class, all of your Car objects that have Doors would automatically inherit those changes. If you wanted to swap out the engine of a car with a more powerful one, you could do that easily by passing in a new instance of the Engine object to your Car object.

You could use structs the same way that you would use classes, but generally you should choose to use a class rather than a struct. Structs should be reserved for types that should have value type semantics, i.e., are small, immutable, etc. For more information on the difference and how to make an informed decision, see this question.

And just in case I failed to convince you that nested classes are the correct approach, I'll conclude by noting that they're also the only way of achieving what you want. That is, beyond hacky solutions like appending a pseudo-namespace to the beginning of each function name (i.e., Car.DoorOpen), which is ugly and doesn't really gain you anything at all.

Upvotes: 3

Gambrinus
Gambrinus

Reputation: 2136

No - you would need to have a nested class door with its own methods. You could add your descriptor to the method name. So you would have

car.DoorOpen();
car.DoorClose();

I'd go for classes, since you may have properties that would apply more to the class door than to car. And add properties of the class door to car.

car.Door.Open();

Upvotes: 1

Related Questions