Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Singleton Pattern over Inherited Classes

I'll begin this question with apologizing for the length of the post. So that I save you some time, my problem is that the class pattern I've got stuck in my head is obviously flawed, and I can't see a good solution.

In a project I'm working on, I need to use operate algorithms on a chunks of data, let's call them DataCache. Sometimes these algorithms return results that themselves need to be cached, and so I devised a scheme.

I have an Algorithm base class that looks like so

abstract class Algorithm<T>
    {
        protected abstract T ExecuteAlgorithmLogic(DataCache dataCache);
        private readonly Dictionary<DataCache, WeakReference> _resultsWeak = new Dictionary<DataCache, WeakReference>();        
        private readonly Dictionary<DataCache, T> _resultsStrong = new Dictionary<DataCache, T>();

        public T ComputeResult(DataCache dataCache, bool save = false)
        {
            if (_resultsStrong.ContainsKey(dataCache))
                return _resultsStrong[dataCache];

            if (_resultsWeak.ContainsKey(dataCache))
            {
                var temp = _resultsWeak[dataCache].Target;
                if (temp != null) return (T) temp;
            }

            var result = ExecuteAlgorithmLogic(dataCache);
            _resultsWeak[dataCache] = new WeakReference(result, true);
            if (save) _resultsStrong[dataCache] = result;

            return result;
        }
}

If you call ComputeResult() and provide a DataCache you can optionally select to cache the result. Also, if you are lucky result still might be there if the GC hasn't collected it yet. The size of each DataCache is in hundreds of megabytes, and before you ask there are about 10 arrays in each, which hold basic types such as int and float.

My idea here was that an actual algorithm would look something like this:

class ActualAgorithm : Algorithm<SomeType>
{
    protected override SomeType ExecuteAlgorithmLogic(DataCache dataCache)
    {
       //Elves be here
    }
}

And I would define tens of .cs files, each for one algorithm. There are two problems with this approach. Firstly, in order for this to work, I need to instantiate my algorithms and keep that instance (or the results are not cached and the entire point is mute). But then I end up with an unsightly singleton pattern implementation in each derived class. It would look something like so:

class ActualAgorithm : Algorithm<SomeType>
{
    protected override SomeType ExecuteAlgorithmLogic(DataCache dataCache)
    {
       //Elves and dragons be here
    }
    protected ActualAgorithm(){ }
    private static ActualAgorithm _instance;
    public static ActualAgorithm Instance
    {
        get
        {
            _instance = _instance ?? new ActualAgorithm();
            return _instance;
        }
    }
}

So in each implementation I would have to duplicate code for the singleton pattern. And secondly tens of CS files also sounds a bit overkill, since what I'm really after is just a single function returning some results that can be cached for various DataCache objects. Surely there must be a smarter way of doing this, and I would greatly appreciate a nudge in the right direction.

like image 289
Gleno Avatar asked Jan 21 '23 21:01

Gleno


1 Answers

What I meant with my comment was something like this:

abstract class BaseClass<K,T> where T : BaseClass<K,T>, new()
{
    private static T _instance;
    public static T Instance
    {
        get
        {
            _instance = _instance ?? new T();
            return _instance;
        }
    }
}

class ActualClass : BaseClass<int, ActualClass>
{
    public ActualClass() {}
}

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(ActualClass.Instance.GetType().ToString());
        Console.ReadLine();
    }
}

The only problem here is that you'll have a public constructor.

like image 165
Tomas Jansson Avatar answered Jan 29 '23 11:01

Tomas Jansson