I have class which handles some UI stuff, lets call that class and instance UI for the example.
inside this class I will have an object of type Colors:
public class Colors {
public ConsoleColor Primary { get; set; } = ConsoleColor.White;
public ConsoleColor Default { get; set; } = ConsoleColor.Gray;
public ConsoleColor Input { get; set; } = ConsoleColor.Gray;
public ConsoleColor Success { get; set; } = ConsoleColor.Green;
public ConsoleColor Error { get; set; } = ConsoleColor.Red;
public ConsoleColor Highlight { get; set; } = ConsoleColor.Blue;
}
Inside UI I have this:
public static class UI {
public static readonly Colors Colors = new();
public static void ConfigureColors(Action<Colors> modification) {
modification.Invoke(Colors);
}
}
The problem is that I want the to be able to access the getters of the Colors property outside UI like this:
var primaryColor = UI.Colors.Primary;
but not the setters... right now, both of these work:
UI.ConfigureColors(colors => {
colors.Primary = ConsoleColor.Yellow;
});
UI.Colors.Primary = ConsoleColor.Green;
but I only want to be able to set the colors using the ConfigureColors() method. I thought it would naturally be like this since I set the Colors property to readonly, but it doesn't work like I wanted.
I tried playing around with the accessability of the properties inside the Colors class, like making them readonly or "private set" but all the modification I thought of caused both the options to not work.
CodePudding user response:
You expose the colors through an interface declaring getter-only properties. An implementation can then have setters as well:
public interface IColors
{
ConsoleColor Primary { get; }
ConsoleColor Default { get; }
ConsoleColor Input { get; }
ConsoleColor Success { get; }
ConsoleColor Error { get; }
ConsoleColor Highlight { get; }
}
public class Colors : IColors
{
public ConsoleColor Primary { get; set; } = ConsoleColor.White;
public ConsoleColor Default { get; set; } = ConsoleColor.Gray;
public ConsoleColor Input { get; set; } = ConsoleColor.Gray;
public ConsoleColor Success { get; set; } = ConsoleColor.Green;
public ConsoleColor Error { get; set; } = ConsoleColor.Red;
public ConsoleColor Highlight { get; set; } = ConsoleColor.Blue;
}
Configure like this:
public static class UI
{
public static readonly IColors Colors = new Colors();
public static void ConfigureColors(Action<Colors> modification)
{
modification.Invoke((Colors)Colors);
}
}
Example of usage:
var primary = UI.Colors.Primary; // Okay
UI.Colors.Primary = ConsoleColor.Gray; // Error CS0200 Property or indexer
// 'ConfigurableColors.IColors.Primary'
// cannot be assigned to --it is read only
CodePudding user response:
You could create an interface that only publishes the getters:
public interface IColors {
ConsoleColor Primary { get; }
ConsoleColor Default { get; }
ConsoleColor Input { get; }
ConsoleColor Success { get; }
ConsoleColor Error { get; }
ConsoleColor Highlight { get; }
}
The class Colors
should implement this interface:
public class Colors: IColors
{
// ...
}
Instead of using the class for the property in the UI
class, you use the interface:
public static class UI {
private static readonly Colors _colors = new();
public static IColors Colors { get => _colors; }
public static void ConfigureColors(Action<Colors> modification) {
modification.Invoke(Colors);
}
}
This blocks write access to the properties when using the UI.Colors.Primary
notation and allows writing with the actions - at least as long as the caller does not cast the interface to the class:
((Colors)UI.Colors).Primary = ConsoleColor.Green;
CodePudding user response:
You may split the Colors class into a readonly interface and a modification interface like this:
public interface IColors {
ConsoleColor Primary { get; }
ConsoleColor Default { get; }
ConsoleColor Input { get; }
ConsoleColor Success { get; }
ConsoleColor Error { get; }
ConsoleColor Highlight { get; }
}
public interface IModifyableColors {
ConsoleColor Primary { get; set; }
ConsoleColor Default { get; set; }
ConsoleColor Input { get; set; }
ConsoleColor Success { get; set; }
ConsoleColor Error { get; set; }
ConsoleColor Highlight { get; set; }
}
Both interfaces would be implemented by the class Colors
(which could be made a private class):
class Colors : IColors, IModifyableColors
{
public ConsoleColor Primary { get; set; } = ConsoleColor.White;
public ConsoleColor Default { get; set; } = ConsoleColor.Gray;
public ConsoleColor Input { get; set; } = ConsoleColor.Gray;
public ConsoleColor Success { get; set; } = ConsoleColor.Green;
public ConsoleColor Error { get; set; } = ConsoleColor.Red;
public ConsoleColor Highlight { get; set; } = ConsoleColor.Blue;
}
Your UI class would then expose the readonly interface only:
public static class UI {
static readonly Colors _colors = new();
public static IColors Colors => _colors;
public static void ConfigureColors(Action<IModifyableColors> modification) {
modification.Invoke(_colors);
}
}