Summary of the problem
Actually I just want to use normal inheritance functionality.
The catch is, that some of my methods are static, so they cannot access the inherited properties like normal.
Furthermore, I cannot pass anything to the static methods (like the instance of the object), because they are called by "external triggers".
On the other side I don't need multiple instances, meaning something like a singleton would be fine.
Let me explain you my situation step by step:
(Or just jump to the first code sample to see the MCV example)
Requirement 1 - Static methods accessing members
I'm using the library Harmony for patching methods of an existing Assembly.
The patching methods must be static and are called by the "hooks" of the library.
I add new player upgrades to a game. For each upgrade I want to patch I create a class with members, like name, description, image ...
One Upgrade must be only patched once, so the solution here would be making everthing static.
But ...
Requirement 2 - Inheritance
Because these upgrades share a lot of common members and methods, I make a BaseUpgrade class and derive from it.
Each specific implementation can now assign their values to the common fields like name, description ... and inherit the rest (the methods using the members).
Yet the members aren't accessible from the static patching methods anymore. For that I can use Singletons.
I want to inherit all the Singleton stuff too, making it generic. This way only the base class has all the Singeton code.
One approach would be this solution: https://stackoverflow.com/a/16865465
However ...
Requirement 3 - Having a Collection of the base class
I need to have collections of the base class and use them in dictionaries (both as key and value). But that doesn't seem to work with generic classes.
I found Collection of generic types, but I'm stuck. I don't know if incorporating this will actually work. At least it would complicate things even more.
Would that work? Is there maybe a much more simple approach to my problem?
MCV Example of the Basic Scenario
using System;
using System.Collections.Generic;
namespace Using_Singleton
{
// This is the version trying to incorperate the inheritable singleton
class Base<T> where T : Base<T>, new()
{
#region Singleton stuff
private static T _instance;
public static T Instance
{
get
{
if (_instance == null)
_instance = new T();
return _instance;
}
set => _instance = value;
}
#endregion
public string name; // Should be accessible by the derived class' static methods
public string desc;
protected Base()
{
name = "Base";
}
public void printName()
{
Console.WriteLine(name);
}
}
class FirstChild : Base<FirstChild>
{
public int number; // Should be accessible by the class' static methods
public FirstChild()
{
name = "The first child";
number = 7;
}
public static void StaticMethod_FirstChild()
{
Console.WriteLine("StaticMethod_FirstChild: I can access all member variables! :-)");
Console.WriteLine("Name: " + Instance.name + ", Number: " + Instance.number); // This is now working
}
}
class SecondChild : Base<SecondChild>
{
public float myfloat;
public SecondChild()
{
name = "The second child";
myfloat = 0.3f;
}
public static void StaticMethod_SecondChild()
{
Console.WriteLine("StaticMethod_SecondChild: I can access all member variables! :-)");
Console.WriteLine("Name 2x: " + Instance.name + " " + Instance.name); // This is now working
}
}
class Manager // Manages instances/singletons which derive from "Base" by using a collection of the Base class
{
//Dictionary<string, Base> itemDict; // ******* This is now broken
public Manager()
{
//itemDict = new Dictionary<string, Base>();
//Base addItem;
//addItem = new FirstChild();
//itemDict.Add(addItem.GetType().Name, addItem);
//addItem = new SecondChild();
//itemDict.Add(addItem.GetType().Name, addItem);
// Simulating the external call of one static method
SecondChild.StaticMethod_SecondChild();
Console.WriteLine();
}
public void DoSomething()
{
//foreach (var item in itemDict)
//{
// item.Value.printName();
//}
}
}
class Program
{
static void Main(string[] args)
{
Manager manager = new Manager();
manager.DoSomething();
Console.ReadLine();
}
}
}
Example using Inheritable Singletons
using System;
using System.Collections.Generic;
namespace Using_Singleton
{
// This is the version trying to incorperate the inheritable singleton
class Base<T> where T : Base<T>, new()
{
#region Singleton stuff
private static T _instance;
public static T Instance
{
get
{
if (_instance == null)
_instance = new T();
return _instance;
}
set => _instance = value;
}
#endregion
public string name; // Should be accessible by the derived class' static methods
public string desc;
protected Base()
{
name = "Base";
}
public void printName()
{
Console.WriteLine(name);
}
}
class FirstChild : Base<FirstChild>
{
public int number; // Should be accessible by the class' static methods
public FirstChild()
{
name = "The first child";
number = 7;
}
public static void StaticMethod_FirstChild()
{
Console.WriteLine("StaticMethod_FirstChild: I can access all member variables! :-)");
Console.WriteLine("Name: " + Instance.name + ", Number: " + Instance.number); // This is now working
}
}
class SecondChild : Base<SecondChild>
{
public float myfloat;
public SecondChild()
{
name = "The second child";
myfloat = 0.3f;
}
public static void StaticMethod_SecondChild()
{
Console.WriteLine("StaticMethod_SecondChild: I can access all member variables! :-)");
Console.WriteLine("Name 2x: " + Instance.name + " " + Instance.name); // This is now working
}
}
class Manager // Manages instances/singletons which derive from "Base" by using a collection of the Base class
{
//Dictionary<string, Base> itemDict; // ******* This is now broken
public Manager()
{
//itemDict = new Dictionary<string, Base>();
//Base addItem;
//addItem = new FirstChild();
//itemDict.Add(addItem.GetType().Name, addItem);
//addItem = new SecondChild();
//itemDict.Add(addItem.GetType().Name, addItem);
// Simulating the external call of one static method
SecondChild.StaticMethod_SecondChild();
Console.WriteLine();
}
public void DoSomething()
{
//foreach (var item in itemDict)
//{
// item.Value.printName();
//}
}
}
class Program
{
static void Main(string[] args)
{
Manager manager = new Manager();
manager.DoSomething();
Console.ReadLine();
}
}
}