The question should be language agnostic, but in this case C# is used.
There are 2 classes: Context
and Context<T>
.
Context
contains MainObject
which is of type dynamic
(can be of type object
as well)
Context<T>
needs to specify more the MainObject
type.
The main purpose is to be able to use the Context
class in services and functions that doesn't have the responsibility of knowing the specific type of MainObject
at compile time.
For example The Serialize
method accepts Context
as an argument while the ResolveUiWidget
method accepts Context<UiWidget>
as parameter. Also if var context = Context<UiWidget>
Serialize(context)` is a valid statement. So this design seems beneficial.
Is this a wrong approach or does it break the SOLID principles and design patterns ? If yes, is there another way of satisfying the parameters of Serialize
and ResolveUiWidget
methods ?
Maybe this is looking too much into the future but as a learning experience, getting a sense that Likov principle can be broken but not able to fully see a scenario.
This is the current code:
public class Context
{
public virtual dynamic? MainObject { get; set; }
}
public class Context<T>: Context
{
public new T? MainObject { get; set; }
public Context()
{
MainObject = base.MainObject;
}
}
I would suggest moving from classes to interfaces, ideally read-only (i.e. with no set
property method).
Why read-only:
Context<int> x = ...;
public void AcceptsBaseContext(Context ctx)
{
ctx.MainObject = "haha";
}
AcceptsBaseContext(x);
IEnumerable
does:public interface IContext
{
object? MainObject { get; }
}
public interface IContext<out T> : IContext
{
new T? MainObject { get; }
}
public class Context<T> : IContext<T>
{
public T? MainObject { get; }
object? IContext.MainObject => MainObject;
public Context(T? obj)
{
MainObject = obj;
}
}
Or you can change the generic interface to:
public interface IContext<T> : IContext
{
new T? MainObject { get; set; }
}
public class Context<T> : IContext<T>
{
public T? MainObject { get; set; }
object? IContext.MainObject => MainObject;
public Context(T? obj)
{
MainObject = obj;
}
}
If you need to write to the property.
Either way method which are context type agnostic can work with it via IContext
interface while you still preserve type safety.