Laden...

Typ einer Klasse ermitteln, um diese dynamisch zu instanzieren

Erstellt von pollito vor 4 Jahren Letzter Beitrag vor 4 Jahren 1.308 Views
pollito Themenstarter:in
314 Beiträge seit 2010
vor 4 Jahren
Typ einer Klasse ermitteln, um diese dynamisch zu instanzieren

Hallo,

ich habe eine Grundsatzfrage, die ich dachte, selbst schnell beantworten zu können – Pustekuchen!

Gegeben eine Vaterklasse "Vater" und zwei davon abgeleiteten Klassen KindA und KindB.

Eine generische Methode sollte ein Objekt einer der beiden Kinder-Klassen erstellen, diese aber in der Vaterklasse speichern.

Hier die Beispielklassen, aus dem Programmcode stark reduziert:

class Vater
{
	public Dictionary<string, string> Fields;

	public void Fill(string[] Rows, Dictionary<string, string> Fields)
	{
		int index = 0;

		foreach (var field in Fields.OrderBy(o => o.Key))
		{
			Fields[field.Key] = Rows[index++];
		}

		this.Fields = Fields;
	}
}

class KindA : Vater
{
	public new Dictionary<string, string> Fields = new Dictionary<string, string>()
	{
		{ "Row01", string.Empty },
		{ "Row02", string.Empty },
		{ "Row03", string.Empty }
	};

	public KindA(string[] Rows) => Fill(Rows, Fields);
}

class KindB : Vater
{
	public new Dictionary<string, string> Fields = new Dictionary<string, string>()
	{ "Row01", string.Empty },
	{ "Row02", string.Empty }
	
	public KindB(string[] Rows) => Fill(Rows, Fields);
}

Nun habe ich zwei Methoden, die eigentlich dasselbe machen, allerdings arbeitet die erste mit der Klasse KindA, während die zweite mit KindB:


public Vater MethodeA(string[] Rows)
{
	Vater Klassenobjekt = new KindA(Rows);

	return Vater;
}

public Vater MethodeB(string[] Rows)
{
	Vater Klassenobjekt = new KindB(Rows);

	return Vater;
}

Ich dachte, ich mache einfach eine Methode daraus, in dem ist sie generisch gestalte und den Datentyp mit angebe:

public Vater Methode<T>(string[] Rows)
{
	Vater Klassenobjekt;

	// ????
	// Klassenobjekt = new KindA(Rows);
	// Klassenobjekt = new KindB(Rows);
	// ????

	return Vater;
}

Und nun weiß ich nicht, wie ich den new-Aufruf generisch gestalten kann. Welche Ansätze gibt es hier?

Klar kann ich darauf verzichten, einen Hinweis auf den Typ als Parameter übergeben und mit if-Abfragen darauf reagieren. Ich fände es aber anders schon eleganter.

Ich freue mich auf eure Anregungen und bedanke mich schonmal im Voraus.

Liebe Grüße und bleibt gesund!

René

16.833 Beiträge seit 2008
vor 4 Jahren

Und nun weiß ich nicht, wie ich den new-Aufruf generisch gestalten kann. Welche Ansätze gibt es hier?

dynamisches new vermeidet man, wenn möglich.

Je nachdem zum Beispiel über den Factory Pattern oder den Builder Pattern.

W
955 Beiträge seit 2010
vor 4 Jahren

... oder Fabrikmethode / factory method.

5.658 Beiträge seit 2006
vor 4 Jahren

Mit einem parameterlosem Konstruktor würde es allerdings funktionieren. Dann mußt du die Daten aber anders übergeben.


public Vater Methode<T>(string[] rows) where T: Vater, new()
{
    var result = new T();
    result.SetData(rows); 
    return result;
}

Weeks of programming can save you hours of planning

4.939 Beiträge seit 2008
vor 4 Jahren

Generisch geht das mit dem new constraint:


public Vater Methode<T>(string[] rows) where T : Vater, new()
{
    T t = new T();
    t.Rows = rows;

    return t;
}

Leider funktioniert der new-Operator im Code nur noch für den Standardkonstruktor - daher mußt du die Parameter dann nachträglich per Eigenschaft oder Methode übergeben.

pollito Themenstarter:in
314 Beiträge seit 2010
vor 4 Jahren

Ich gehe Kaffee zapfen und schon werde ich mit Antworten überrollt. Klasse!

@Abt und @witte
Ich werde mich damit auseinandersetzen. Danke für die Denkanstöße!

@MrSparkle und @Th69
Auch euch beiden lieben Dank!

...
T t = new T();
...
var result = new T();

"t" bzw. "result" sollten immer des Typen "Vater" sein.

Wenn ich das versuche, sagt mir VS: > Fehlermeldung:

Es kann keine Instanz des Variablentyps "T" erstellt werden, weil er keine new()-Einschränkung aufweist. – Muss auch danach schauen.

Nochmals vielen Dank!

René

16.833 Beiträge seit 2008
vor 4 Jahren

"t" bzw. "result" sollten immer des Typen "Vater" sein.

Warum? Was hast Du denn eigentlich vor?
Eventuell hast nen Designfehler im Code und das hier ist nen Folgefehler.

Th69's Variante sollte trotzdem gehen.

pollito Themenstarter:in
314 Beiträge seit 2010
vor 4 Jahren

(...) Was hast Du denn eigentlich vor?
Eventuell hast nen Designfehler im Code und das hier ist nen Folgefehler.

Das will ich nicht ausschließen.

Ich habe viele gleich aufgebaute Datenstrukturen, welche in Dictionaries verwaltet werden. Allerdings unterscheiden sich diese nicht nur in der Anzahl von Einträgen, sondern die Schlüssel können auch anders heißen.

public new Dictionary<string, string> Fields = new Dictionary<string, string>()
{
    { "Row01", string.Empty },
    { "Row02", string.Empty },
    { "Row03", string.Empty }
};
...
public new Dictionary<string, string> Fields = new Dictionary<string, string>()
{
    { "Column0A", string.Empty },
    { "Column0B", string.Empty }
};

Dabei gibt es einen großen Satz an Methoden, die für alle abgeleiteten Klassen Anwendung findet. Je nach Datenstruktur einer der abgeleiteten Klassen, bieten diese aber auch zusätzlich unterschiedliche Funktionalität. Wenn man z. B. an Datenbanktabellen denkt, gibt es für deren Verwaltung Funktionalität, die alle Datenbanktabellen gleichermaßen betrifft – diese beherbergt die Vaterklasse. Nun gibt es aber auch tabellenspezifische Funktionalität: Eine formatierte Anschrift für die abgeleitete Klasse "Kunde" oder online errechnete Artikelpreise in unterschiedlichen Währungen für die Abgeleitete Klasse "Artikel".

So grob lässt es sich beschreiben.

Klar kann ich alle Klassen umschreiben und diese als getrennte Klassen auslegen. Die ehemals "Vaterklasse" wird dann von den anderen Klassen instanziert – also alles ohne Vererbung, Polymorphie o. ä.

Ich hoffe, ich konnte das einigermaßen klar erklären.

Th69's Variante sollte trotzdem gehen.

Ja, es geht. Ich hatte einen doofen Tippfehler – sorry für die Verwirrung!

LG

René

5.658 Beiträge seit 2006
vor 4 Jahren

Ich habe viele gleich aufgebaute Datenstrukturen, welche in Dictionaries verwaltet werden.

Ich sehe hier aber keine Datenstrukturen, sondern nur Dictionarys mit Magic Strings. Was spricht gegen Klassen mit Eigenschaften, bzw. OOP?

Weeks of programming can save you hours of planning

pollito Themenstarter:in
314 Beiträge seit 2010
vor 4 Jahren

Ich sehe hier aber keine Datenstrukturen, sondern nur Dictionarys mit Magic Strings. Was spricht gegen Klassen mit Eigenschaften, bzw. OOP?

Sicher, es soll lediglich ein Beispiel über den Aufbau sein. Der echte Code würde die Fragestellung unnötig verkomplizieren.

René

16.833 Beiträge seit 2008
vor 4 Jahren

Es wäre trotzdem toll, wenn Du in Zukunft nicht zu viel Informationen oder eben gar Strukturen wie hier verschleierst / verfremdest.
Das läuft sonst immer auf Missverständnisse wie auch hier hinaus und das bringt dann keinem was.