5

I have a base class and several derived classes (for example Base and ChildA : Base). Each time I create an instance of ChildA class, I want it to be assigned a unique instance number (similar to autoincrement IDs in relational databases, but for my classes in memory as opposed to in a database).

My question is similar to this one, but there is one distinct difference: I would like the base class to handle this automatically. For each of my derived classes (ChildA, ChildB, ChildC, etc.), I would like the base class to maintain a separate count and increment this when a new instance of that derived class is created.

So, the information held in my Base class might end up looking like this:

ChildA,5
ChildB,6
ChildC,9

If I then instantiate a new ChildB (var instance = new ChildB();), I would expect ChildB to be assigned the id 7, since it follows on from 6.

Then, if I instantiate a new ChildA, I would expect ChildA to be assigned the id 6.

-

How can I handle this within the constructor of my Base class?

ProgrammingLlama
  • 36,677
  • 7
  • 67
  • 86
Mobz
  • 344
  • 1
  • 16
  • What have you tried already? Where specifically are you stuck? – MakePeaceGreatAgain Oct 18 '18 at 08:05
  • @SerhiiVoichyk this isn't a duplicate of that. the other question does not deal with derived classes – adjan Oct 18 '18 at 08:06
  • 1
    @SerhiiVoichyk - almost all of those answers use a single static variable, which isn't going to work here where we're trying to put the functionality in a base class – Damien_The_Unbeliever Oct 18 '18 at 08:06
  • To me it seems every *derived* class has its own counter, not the *base*-class. Making it a good fit for the duplicate. – MakePeaceGreatAgain Oct 18 '18 at 08:07
  • @HimBromBeere He wants to have the **whole logic in the base class**. It's not a diuplicate. I hate this "close bc duplicate" on SO when it's not. – adjan Oct 18 '18 at 08:09
  • @Adrian I agree that this point differes from the duplicate. However I would hold the question on hold, because it´s unclear what OP actually wants and what he has tried already, making it to be closed as unclear anyway. There´s no way to answer that question other than **guessing**. – MakePeaceGreatAgain Oct 18 '18 at 08:14
  • @HimBromBeere On hold is fine. I just think an answer would be valuable though, if the question was better imo. – adjan Oct 18 '18 at 08:15
  • @Adrian You´re right in **if** the question was better phrased. Currently any pootential answer is just a guess. – MakePeaceGreatAgain Oct 18 '18 at 08:17
  • 1
    @Mobz, better explain your question, show what you have tried, and i am sure this will be reopened – TheGeneral Oct 18 '18 at 08:21
  • My problem is I'm working in the dark on this, I don't really know where to start. I'm not sure how to explain it any better.. As @HimBromBeere said it is important to me that the Whole logic is in the base class. I don't want to copy the same code into all my class's – Mobz Oct 18 '18 at 08:28
  • Are you saying that you want each derived type to have its own auto-incrementing id set, where each time you instantiate the derived class, it increments that id by 1, but you want that logic to live in the base class? – ProgrammingLlama Oct 18 '18 at 08:30
  • @John Yes that is want im looking for! – Mobz Oct 18 '18 at 08:34
  • 1
    Could you please add this information to your question together with some sample-classes that show your class-hierarchy and where the counter should be accessable/defined? Makes it much easiert to get an image of your story. – MakePeaceGreatAgain Oct 18 '18 at 08:35
  • @Mobz I have edited your question (after your edit, I know) to (hopefully) more clearly illustrate what you're trying to achieve. Feel free to roll it back if it isn't what you want. – ProgrammingLlama Oct 18 '18 at 08:45
  • @John I´m not that convinced, if editing the question so heavily really maintains the original OPs intent. – MakePeaceGreatAgain Oct 18 '18 at 08:48
  • Thank you very much @John! That is really kind of you. You hit the nail on the head with that edit. – Mobz Oct 18 '18 at 08:48
  • @HimBromBeere Yeah, I know what you mean. It seems I was correct in my understanding though :) – ProgrammingLlama Oct 18 '18 at 08:49

2 Answers2

6

You could use a static Dictionary<Type, int> inside the base class where you keep track of derived instances by type. Since this will be of the derived type, you can use this.GetType() as the key inside the dictionary.

class Base
{
    static Dictionary<Type, int> counters = new Dictionary<Type, int>();
    public Base()
    {
        if (!counters.ContainsKey(this.GetType()))
            counters.Add(this.GetType(), 1);
        else
            counters[this.GetType()]++;
        Console.WriteLine(this.GetType() + " " + counters[this.GetType()]);
    }
}

class Derived : Base
{
}

class Derived2 : Base
{
}

public static void Main()
{
    new Derived();
    new Derived2();
    new Derived();
}

Output:

Derived 1 
Derived2 1
Derived 2

For thread safety, you can use a ConcurrentDictionary<K,V> instead of Dictionary<K,V>.

adjan
  • 13,371
  • 2
  • 31
  • 48
  • `ConcurrentDictionary`? https://learn.microsoft.com/de-de/dotnet/api/system.collections.concurrent.concurrentdictionary-2.tryadd?redirectedfrom=MSDN&view=netframework-4.7.2 – adjan Oct 18 '18 at 08:54
  • You should use `counters.TryGetValue` instead of `counters.ContainsKey`. This will prevent looking for a key twice. – Stanislav Dontsov Oct 18 '18 at 08:54
  • 2
    Are you asking or saying? this is your answer, I was just commenting on it. If you think a concurrentDictionary is a better solution, you should edit that into your answer. – Zohar Peled Oct 18 '18 at 08:55
  • 1
    @ZoharPeled Wel, it´s not explicitely mentioned in the question, so I wouldn´t specifically consider this. – MakePeaceGreatAgain Oct 18 '18 at 09:00
  • Thank you @Adrian for at great solution! It is now a part of my code and works great! And thank you all for your comments! Thanks John for making my question more Stackoverflow friendly - which is a skill I surely lag! – Mobz Oct 18 '18 at 12:35
0

Or a thread safe version

public class BaseClass
{
   public static ConcurrentDictionary<Type,int> Counter = new ConcurrentDictionary<Type, int>();   
   public BaseClass() => Counter.AddOrUpdate(GetType(), 1, (type, i) => i + 1);
}

Usage

for (int i = 0; i < 2; i++)
   Console.WriteLine("Creating " + new A());

for (int i = 0; i < 4; i++)
   Console.WriteLine("Creating " + new B());

for (int i = 0; i < 1; i++)
   Console.WriteLine("Creating " + new C());

foreach (var item in BaseClass.Counter.Keys)
   Console.WriteLine(item + " " + BaseClass.Counter[item] );

Ouput

Creating ConsoleApp8.A
Creating ConsoleApp8.A
Creating ConsoleApp8.B
Creating ConsoleApp8.B
Creating ConsoleApp8.B
Creating ConsoleApp8.B
Creating ConsoleApp8.C
ConsoleApp8.A 2
ConsoleApp8.C 1
ConsoleApp8.B 4

Full Threaded Demo Here

TheGeneral
  • 79,002
  • 9
  • 103
  • 141