Continuing with the answer given here, is there a way to allow MyChildSingleton to be abstract, and then let it's sub-classes define their own constructors? An example of what I would like to do:
public abstract class SingletonBase<T>
where T : SingletonBase<T>, new()
{
private static T _instance = new Lazy<T>(() => new T());
public static T Instance
{
get
{
return _instance;
}
}
}
public abstract class DefaultConfigData: SingletonBase<DefaultConfigData>
{
// This class won't compile since it's abstract, and SingletonBase<T>
// has a new() restriction on T
// Also, this class is immutable and doesn't change state
public virtual string SomeData { get; } = "My Default Data String";
public virtual double MoreData { get; } = 2.71;
public virtual double SomeFunction(double num)
{ return num + 2*MoreData; }
public DefaultConfigData() { ; /* nothing to do here */ }
// Another 50 or so default values/functions...
// enough to be tedious to redefine in multiple places,
// and adding a constructor that takes every value would be ridiculous.
// It would be possible to encapsulate this data, but I'm not
// yet sure how this should be done, so I haven't gone there yet
}
public class SpecificConfigData1: DefaultConfigData
{
public override string SomeData { get; } = "A Different String";
public SpecificConfigData1() { ; /* nothing to do here */ }
}
public class SpecificConfigData2: DefaultConfigData
{
public override double MoreData { get; } = 3.14;
public SpecificConfigData2() { ; /* nothing to do here */ }
}
// Downstream developers may need to define additional ConfigData classes
public class Library
{
public static double doSomething(DefaultConfigData data) { return data.MoreData + 2.0; }
}
public class Program
{
private readonly DefaultConfigData data;
public Program(bool choice)
{
data = (choice) ? SpecificConfigData1.Instance : SpecificConfigData2.Instance;
}
public static void Main()
{
Program prog = new Program(/*run-time user input here*/);
Console.PrintLine(Library.doSomething(prog.data));
}
}
Using a singleton pattern seemed like a good idea, because for each specific subclass the data only needs to exist in one place, and since it's immutable this avoids most of the issues associated with singletons (global mutable state, etc.). Providing the singleton functionality in an abstract base class would avoid the boilerplate of putting the private instance and public get property, which is what I'm doing now in each sub-class. This really isn't too onerous a requirement, I'm sure I could live with it.
I don't want to make DefaultConfigData and it's data static, because then I can't inherit from it and have my library functions know how to interact with it (no support for metaclasses in C#). Also, I don't want to use an interface, because so much of the functionality is shared, and I couldn't define that in the interface.
I would also welcome comments on alternative approaches, if the one I'm trying to do can't be accomplished, or if another way is simply easier. I know that a factory pattern could also work here, and that's something I intend to try eventually.
Last, why is this even an issue? Why wasn't the decision made to let abstract classes satisfy the new() requirement, provided that any of their sub-classes also satisfy a new()?
Note that my "users" are other internal developers/my future self. Source code is usually the deliverable, and pushing checks to run time are ok in this environment.