Hergine Richemont

Learning just for the fun of it

C# Track,Exercism #40 Remote control cleanup

Relevant link

Github solution: exercism-solutions/remote-control-cleanup

Exercism #40: C# exercises on Exercism

Relevant information

C# types can be defined within the scopes of a class or a struct.

Access to the type is through the enclosing type with dot syntax.

You can set access level for inner types.

Private members of the outer type are in scope for members of the inner typebut not vice versa.

Task #1: Separate concerns between the car itself and the telemetry system

I created a nested CarTelemetry class inside the RemoteControlCar class, and I created a Telemetry property to access the telemetry class functionality.

After creating the CarTelemetry class to separate from the RemoteControlCar class anything related to telemetry, I got 2 errors.

  • For the ShowSponsor method: An object reference is required for the non-static field, method, or property ‘RemoteControlCar.SetSponsor(string)’
  • For SetSpeed method: There is no argument given that corresponds to the required parameter ‘unitsString’ of ‘RemoteControlCar.Telemetry.SetSpeed(decimal, string)’

Question & Prompt to AI: Why when two methods belonging to the same class it is not an issue that one call another, but it generates errors when one of them move to an inner class in c#?

Answer:

In C#, a nested (inner) class is just a class that lives inside the namespace/scope of another class. It does not automatically get a reference to an instance of its outer class.

When both methods are in the same class, they share the same instance (this). But once you move one method to an inner class, you are dealing with two completely separate object instances that don’t know how to talk to each other without explicit instructions.

~ Gemini

Based on the same answer I got cleared that there are 2 ways to resolve the issue:

  1. If the outer is calling a method the inner: The outer has to instantiate the inner class
  2. If the inner is calling a method in the outer: We have to explicitly pass a reference of the outer class to the inner type.

So, I pass a reference of the RemoteControlCar instance to the CarTelemetry class

Task #2: Prevent other code taking too many dependencies on the Telemetry type

Then it says: Ensure that the `Telemetry` instance cannot be created outside the scope of the car.

Question & Prompt to AI: If I have an Inner and an Outer class, how can I make instance of the inner class only accessible to the outer class and nowhere else?

Answer:

  • Use a Private Inner Class when the logic is a strict, permanent, and highly specific internal helper detail of the outer class that will never need to change or be swapped.
  • Use an Interface if you want to follow clean architecture principles, write unit tests easily, or expect that you might need different versions of that internal logic down the road.

I created an interface ITelemetry to define the CarTelemetry functionality and I made the Telemetry property being typed of the interface.

Task 3

Prevent other code from taking dependencies on the Speed struct.

Question and prompt to AI: What access level can I use for struct?

Answer:

In C#, structs are value types used for small, lightweight structures.

  • Default Access: internal (if declared directly in a namespace) or private (if nested inside another class/struct). Members inside the struct default to private.
  • Available Levels:
    • public: Access is unrestricted.
    • internal: Access is limited to the current assembly (project).
    • private: Access is limited to the containing struct.
    • file: Access is limited to the current source file.
    • Note on protected: Structs do not support inheritance, so protected, protected internal, and private protected are not allowed inside a struct.

Obviously I went for internal

Task 4

Prevent other code from taking dependencies on the SpeedUnits enum

Question and prompt to AI: What access level can I use for an enum?

Answer:

If you declare your enum directly inside a namespace (not nested inside a class or struct), it can only have two access levels:

  • public: Access is completely unrestricted. Any other code in your project (or other projects referencing it) can use it.
  • internal (Default): Access is limited to the current assembly (project). If you don’t type an access modifier, it defaults to internal.

I also went for internal.


How would you approach this exercise differently?