C# Klasse eine dynamische ID zuweisen

Rooky420

Cadet 4th Year
Registriert
Nov. 2015
Beiträge
98
Hallo,

ich versuche eine Klasse zu schreiben die für jede unterklasse eine dynamische id erstellt. Also nicht eine id pro instanz sondern eine id pro Klasse. Das versuche ich so zu regeln dass die Unterklassen bei denen die ID erstellt wird absolut nichts machen müssen damit die ID passt.

Code:
Oberklasse
 |             / Unterklasse11
 |-Unterklasse1
 |             \ Unterklasse12
 |
 |-Unterklasse2


In diesem beispiel könnte es dann sein dass es folgendermaßen aussiet:
Oberklasse ID: 0
Unterklasse1 ID: 1
Unterklasse2 ID: 2
Unterklasse11 ID: 3
Unterklasse12 ID: 4

Dabei ist es mir auch völlig egal welche klasse welche id bekommt sie muss nur einzigartig sein.
Ist das irgendwie möglich? Ohne C++ mit den statischen variablen in methoden bekomm ich das irgendwie nicht hin.

Meine aktuelle Klasse (Diese ist falsch sie erstellt für jede "instanz" jeder unterklasse eine eindeutige id):
Code:
abstract class Oberklasse
    {
        private static int id = 0;
        internal readonly int ID = getNextID();
        private static int getNextID()
        {
            return id++;
        }
    }

Das ergebnis der richtigen lösung sollte dann sein:
Code:
            Unterklasse1 t1 = new Unterklasse1 ();
            int i1 = t1.ID; //ID ist 0
            Unterklasse2 t2 = new Unterklasse2();
            int i2 = t2.ID; //ID ist 1
            Unterklasse12 t3 = new Unterklasse12();
            int i3 = t3.ID; //ID ist 2
            Unterklasse1 t4 = new Unterklasse1();
            int i4 = t4.ID; //ID ist 0
            Unterklasse12 t5 = new Unterklasse12();
            int i5 = t5.ID; //ID ist 2
Also für jede Klasse die ID eindeutig und alles in der Oberklasse Programmiert.

Bitte nicht nach dem Sinn oder ähnliches fragen. Ich brauche es einfach so.

Lg
Rooky420
 
Zuletzt bearbeitet:
Weiß nicht ob das funktioniert, aber gibt es nicht vielleicht einen Befehl der Abfragt ob es schon eine Instanz der Klasse gibt und wenn ja kannst du ja die schon vergebene ID dieser Klasse der neuen zuweisen.

So haben alle Klassen der selben Instanz die selbe ID
 
Im Konstruktur einfach die Variable hochzählen.
 
So funktioniert es in Java. getClass muss durch GetType ersetzt werden und Map/HashMap durch Dictionary. Eine andere Möglichkeit ist, das ID-Feld in der Hauptklasse und jeder Unterklasse erneut static zu definieren und zu initialisieren. Static-Felder werden nur ein einziges Mal pro Klasse initialisiert. Der Nachteil ist, wenn man castet, ändert sich der Wert von ID. Das Problem besteht bei der Lösung unten nicht.

Code:
import java.util.HashMap;
import java.util.Map;

public class App {
	public static void main(String[] args) {
		System.out.println("Main " + new Main().ID);
		System.out.println("Sub1 " + new Sub1().ID);
		System.out.println("Sub2 " + new Sub2().ID);
		System.out.println("Sub1 " + new Sub1().ID);
	}
}

class Main {
	public final int ID = IdGen.nextId(this.getClass());
}
class Sub1 extends Main { }
class Sub2 extends Main { }

class IdGen {
	private static int counter = 0;
	private static Map<Class<?>, Integer> idMap = new HashMap<Class<?>, Integer>();

	public static int nextId(Class<?> cls) {
		Integer id = idMap.get(cls);
		if(id == null) {
			id = counter++;
			idMap.put(cls, id);
		}
		return id;
	}
}

Code:
Main 0
Sub1 1
Sub2 2
Sub1 1
 
Du musst dir eigentlich nicht die Mühe machen das selbst zu implementieren, denn jeder Typ ist eindeutig identifizierbar:
Code:
var foo = new Foo();
int id = foo.GetType().GetHashCode()

Btw wenn du einfach nur auf Typgleichheit prüfen willst dann geht das auch einfach so:
Code:
bool isFoo = foo is Foo;
 
Zuletzt bearbeitet:
Guten Morgen,

Danke für die Antworten gestern Abend.
Momentan sieht es bei mir so aus:
Code:
    abstract class Component
    {
        internal readonly int ID = IDGen.getID(this);
    }

    private class IDGen
    {
        private static int counter = 0;
        private static Dictionary<Type, int> ids = new Dictionary<Type, int>();

        public static int getID(Component component)
        {
            int value;
            if(ids.TryGetValue(component.GetType(), out value))
                return value;
            else
            {
                ids.Add(component.GetType(), counter);
                return counter++;
            }
        }
    }

Leider makiert Visual Studio diese Zeile da man "this" nicht im aktuellen kontext verwenden darf:
Code:
IDGen.getID(this);

Gibt es irgendeine andere möglichkeit die aktuelle instanz oder den Typ der aktuellen instanz zu übergeben?
 
this ist erst im Konstruktur verfügbar. Setz den Inhalt von ID im Konstruktor von Component.

Warum nicht mit der Methode von Grantig?
Code:
class Program
{
	static void Main(string[] args)
	{
		Component A1 = new ComponentA();
		Component B1 = new ComponentB();
		Component C1 = new ComponentC();
		Component A2 = new ComponentA();
		Component B2 = new ComponentB();
		Component C2 = new ComponentC();

		Console.WriteLine($"A1: {A1.ID} | A2: {A2.ID} | B1: {B1.ID} | B2: {B2.ID} | C1: {C1.ID} | C2: {C2.ID}");
		Console.ReadLine();
	}
}

public abstract class Component
{
	public int ID { get; }

	public Component()
	{
		ID = GetType().GetHashCode();
	}
}

public class ComponentA : Component
{
}

public class ComponentB : Component
{
}

public class ComponentC : Component
{
}

Ergebnis:
Code:
A1: 62476613 | A2: 62476613 | B1: 11404313 | B2: 11404313 | C1: 64923656 | C2: 64923656

EDIT: Zeile 12 und 19/23 sind übrigens C# 6.0 Features und erst mit VS 2015 nutzbar.
 
Zuletzt bearbeitet:
Warum nicht mit der Methode von Grantig?

Der Grund warum ich diese methode gewählt habe ist dass die ID der Klasse später im programm auf ein array verweist wodurch es besser ist IDs wie "0, 1, 2..." zu haben.
 
Evtl. ist ein Array auch nicht die richtige Datenstruktur für das was du machen willst.
Ein Dictionary könnte besser geeignet sein.

Aber um ne brauchbare Empfehlung abzugeben müsstest du noch etwas mehr darüber verraten was du eigentlich vorhast.
 
Ich finde interessant, wie im zweiten Beitrag Yuuri die einfachste Lösung sagt aber jeder versucht, das möglichst komplizierteste rauszukramen :evillol:.

Also zähle doch einfach in deiner abstracten Klasse und setze dann eine weiter statische ID in der Kindklasse. Ich denke das sollte ganz ohne Code-Beispiel gehen :)

Beste Grüße und Viel Spaß beim programmieren

#EDIT ich gebe vielleicht doch die Lösung an :p:
Code:
abstract class cbClass
    {
        protected static int _id = 0;

        protected int id;
        public int ID
        { get { return id; } }

        public cbClass()
        { }
    }

    class cbChild : cbClass
    {
        protected static int? __id;
        public cbChild() { if (__id == null) __id = _id++; id = __id.Value; }
    }
Das ergibt dann das von dir gewünschte Muster:
Code:
            int i1 = new cbChild().ID; //ID ist 0
            int i2 = new cbChild2().ID; //ID ist 1
            int i3 = new cbChild3().ID; //ID ist 2
            int i4 = new cbChild().ID; //ID ist 0
            int i5 = new cbChild3().ID; //ID ist 2
 
Zuletzt bearbeitet:
@PapstRatze
Weil er genauso wie du die Frage falsch verstanden hat.
Es soll nicht jede Instanz ne eigene ID bekommen, sondern jeder Typ (jede Klasse).

Bei deiner Lösung muss er genau das machen was er vermeiden wollte und warum die Frage überhaupt aufkam:
Rooky420 schrieb:
Das versuche ich so zu regeln dass die Unterklassen bei denen die ID erstellt wird absolut nichts machen müssen damit die ID passt.
 
Zuletzt bearbeitet:
Okay, ich entnahm der Fragestellung nicht die Pflicht das Kindklassen nichts machen dürfen. Las es als sei es nur die zum Zeitpunkt gewählte Herangehensweise.

Unabhängig bleibt es dabei, er kann das relativ schlicht im Konstruktor lösen...

Weil es scheinbar anders nicht geht, mit Lösung:
Code:
abstract class CBase
    {
        static Dictionary<Type, int> idHandler = new Dictionary<Type, int>();
        public int ID
        { get; private set; }

        public CBase()
        {
            var kvp = idHandler.FirstOrDefault(x => x.Key == this.GetType());
            if (kvp.Key != null)
                ID = kvp.Value;
            else
            {
                ID = idHandler.Count;
                idHandler.Add(this.GetType(), ID);
            }
        }
    }
 
Mir erschließt sich ebenfalls der Nutzen nicht. Ich habe das Gefühl, dass das Grunddesign hier schlichtweg falsch ist. Eine verdächtige Antwort ala "Nicht fragen 'Wieso?'" gibt es ja vom TE schon.
Also ohne weitere Informationen wird es hier nur Zufallsantworten auf imaginäre Fragen/Probleme geben, ohne letztendlichen Bezug und einer Lösung bzw. einer entsprechenden Empfehlung.
 
Ich kann mich nur meinem Vorredner anschließen.
Wenn ich schon höre, dass die Klassen IDs irgendwie genutzt werden auf ein Array zuzugreifen, gehen bei mir alle meine Architektur Alarmglocken an.

Poste doch erstmal eine Beschreibung der Funktion die du implementieren möchtest und dann kann dir sicherlich geholfen werden.
 
Zurück
Oben