Hallo zusammen,
ich möchte einer Methode einen Klassennamen als Parameter übergeben.
Also praktisch folgendermaßen:
public class Auto()
{
...
}
public class Person()
{
...
}
public class TuWasMitDerKlasse(Klasse)
{
...
}
Die Klasse "TuWasMitDerKlasse" bekommt in diesem Fall also entweder "Auto" oder "Person" als Parameter übergeben.
Habs schon versucht mit
public class TuWasMitDerKlasse(typeof(Klasse))
{
...
}
oder mit
public class TuWasMitDerKlasse(class Klasse)
{
...
}
Geht beides nicht. Kann mir jemand vielleicht eine Tipp geben?
Danke und Gruß
Frank
Bist du eventuell auf der Suche nach Generics?
An der Stelle aber der Hinweis: Nur weil du etwas generisch machen kannst, heißt das nicht notwendigerweise, dass du es auch generisch machen solltest. Aber das kannst du nur selbst aufgrund deiner Anforderungen feststellen.
Die wichigste Frage ist ja, was du erreichen möchtest. Was soll denn in TuWasMitDerKlasse passieren?
Willst du eine Instanz übergeben oder tatsächlich nur den Typ?
public class TuWasMitDerKlasse(Klasse)
Das ist im übrigen alles, nur keine gültige Notation zur Definition einer Klasse.
Wie BhaaL gehe ich davon aus, dass du nach Generics suchst. Also etwas in der Richtung:
public class TuWasMitDerKlasse<TKlasse>
{
public TuWasMitDerKlasse(TKlasse klasse)
{
}
}
Allerdings erschließt sich mir nicht, was Auto und Person gemeinsam haben könnten, dass sie mit einer gemeinsamen Verarbeitungslogik verarbeitet werden könnten.
Wissen ist nicht alles. Man muss es auch anwenden können.
PS Fritz!Box API - TR-064 Schnittstelle | PS EventLogManager |
Generics machen aber nur Sinn, wenn die Klassen über eine gemeinsame Basisklasse (bzw. Interface) verfügen, ansonsten kann innerhalb der generischen Methode nur auf Methoden von Object
zugegriffen werden.
Die andere Möglichkeit wäre (du warst schon fast auf dem richtigen Weg):
public void TuWasMitDerKlasse(Type type)
{
...
}
Und dann als Parameter typeof(Auto)
übergeben - aber auch hier kannst du dann direkt nur auf Methoden der Klasse Type
zugreifen, d.h. Reflection benutzen.
PS: Als Rückgabewert class
bei der Methode zu benutzen, war hoffentlich nur ein Schreibfehler (und kein Verständnisfehler)?!
Hallo CrocodileDundee,
vielleicht verstehe ich die Sache auch falsch, aber wieso kannst du nicht ein Interface nehmen und das als Parameter übergeben?
public interface IIrgendwas
{
TuEtwas();
}
public class Auto : IIrgendwas
{
TuEtwas() { ... }
}
public class Person()
{
TuEtwas() { ... }
}
public class TuWasMitDerKlasse(IIrgendwas klasseDieInterfaceImplementiert)
{
klasseDieInterfaceImplementiert.TuEtwas();
}
Reflection würde ich nicht einsetzen, wenn du es nicht musst.
Gruss
Coffeebean
Microsoft MVP // Me // Blog // GitHub // @Egghead // All my talks // Speakerdeck
Im Fall des Interfaces wäre aber das besser
public void TuWasMitDerKlasse<T>(T klasseDieInterfaceImplementiert) where T: class, IIrgendwas
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Huhu, das ist keine ketzerische Frage sondern ernst gemeint. Warum das als generic übergeben?
Das "besser" war aus dem Auge als Software Architekt.
Gründe zB Why use constraints
Du kannst eben auf ein Generic Einschränkungen setzen, die eben bei einfacher Parametrisierung nicht möglich sind.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
hm,
die brauche ich aber auch nicht, wenn ich den Parameter vom Typ IIrgendwas mache.
Welchen Vorteil bekomme ich davon statt
void foo(IIrgendwas param)
void foo<T>(T param) where t: class, IIrgendwas
zu machen?
Das ist, für mich gesehen, der gleiche Aufruf nur komplizierter
hm,
die brauche ich aber auch nicht, wenn ich den Parameter vom Typ IIrgendwas mache.
Schau Dir bitte den Link an und wie Generics funktionieren.
Das ist eben auch ein Thema von Software Design.
public class A
{
public void Test()
{
IIrgendwas a = new Etwas();
Etwas b = new Etwas();
TuWasMitDerKlasse(a);
TuWasMitDerKlasse(b);
}
public void TuWasMitDerKlasse(IIrgendwas klasseDieInterfaceImplementiert) {}
public void TuWasMitDerKlasse<T>(T klasseDieInterfaceImplementiert) where T : class, IIrgendwas { }
}
Die Übergabe mit A ruft die Methode mit Interface als Parameter auf.
Die Übergabe mit B eben die Methode mit Interface über die generische Einschränkung auf.
Fällt Dir was auf? 😃
der gleiche Aufruf nur komplizierter
Das ist eine subjektive Aussage (ähnlich wie mein "Besser" ohne Erklärung 😉
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Sorry, kantische Lehrmethoden funktionieren bei mir heute nicht.
Was ist der Benefit davon, dass ich den Aufruf über ein Generic mache? Und bitte nicht wieder auf den Artikel mit den contstaints verweisen. Der hat mit meiner Frage irgend wie nichts zu tun.
Grüße
Naja; nur weil Du jetzt keine Lust einen Artikel zu lesen, der genau Deine Frage behandelt oder Dich mit Generics und deren Hintergrund nicht beschäftigen magst, springe ich noch lange nicht - nur weil Du schreist 😉
Wenn für Dich das mit den Generics keinen Sinn macht: okay, kann ich mit leben.
Nutzbar ist hier beides. Mein Hinweis es auf positive Art zu Nutzen, gerade was die Möglichkeiten und Erweiterbarkeiten betrifft, der bleibt.
Viel Erfolg 😃
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Ich hab mir aus "Verzweiflung" noch mal deine erste Antwort langsam durchgelesen und bin auf diesen Satz gestoßen.
Das "besser" war aus dem Auge als Software Architekt.
Du kannst eben auf ein Generic Einschränkungen setzen, die eben bei einfacher Parametrisierung nicht möglich sind.
Dein Aufruf startet quasi mit einer Whitelist und schränkt diese dann nachträglich ein (bildlich gesprochen).
Das Interface als Parameter anzugeben schränkt hingegen gleich maximal ein. Was ja an der Stelle für mich Sinnvoll zu sein scheint.
Das enzige, was mir an der Stelle dazu einfällt ist Erweiterbarkeit, falls ich mal ein weiteres Interface supporten soll. Allerdings soll man ja seine Software auch nicht auf absolut jeden möglichen Fall auslegen (overengineering).
iwarum DU das so vorgeschlagen hast. Warum denkst du, ist es besser ein Generic zu benutzen statt das Interface als Parameter zu nehmen.
Es ist ein grundlegendes Thema:
Das ist eben auch ein Thema von Software Design.
Du kannst eben auf ein Generic Einschränkungen setzen, die eben bei einfacher Parametrisierung nicht möglich sind.
Das "Grundproblem", dass die Leute keine Constraints kennen, aber kennen sollten.
Denn viele Dinge lassen sich über constraints viel einfacher lösen - zur Compile Zeit - während man immer wieder über Implementierungen stolpert, die instabil zur Laufzeit geprüft werden.
Prinzip: turning runtime errors into compile time errors.
Zusätzlich natürlich das Cast-Thema, zB. bei Rückgaben des Eingangsparameters bei solchen Methoden.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Auch ich sehe hier keinen Vorteil in der generischen Variante. Beides wird vom Compiler zur Compile-Zeit geprüft.
Und auch die Einschränkung "class
" ist bei Angabe eines Interfaces überflüssig, denn Interfaces funktionieren generell nur bei Klassen (nicht bei Strukturen).
Und worauf du, @Abt, mit deinem Code-Beispiel hinaus willst, kann ich auch nicht sehen?
Hallo,
Und auch die Einschränkung "class" ist bei Angabe eines Interfaces überflüssig, denn Interfaces funktionieren generell nur bei Klassen (nicht bei Strukturen).
Nur zur Richtigstellung: Das stimmt nicht. Auch Strukturen können Interfaces implementieren, und dann auch in auf diese Interfaces eingeschränkten Generics benutzt werden.
Gruß, MarsStein
Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca
Ups, hast recht - habe mich davon verleiten lassen, daß Strukturen keine Basisklassen haben können.
Jedoch gibt es wohl Boxing-Probleme damit: C#: structs and Interface
Meine Hauptfrage an Abt bleibt aber bestehen.
Das "Grundproblem", dass die Leute keine Constraints kennen, aber kennen sollten.
Denn viele Dinge lassen sich über constraints viel einfacher lösen - zur Compile Zeit - während man immer wieder über Implementierungen stolpert, die instabil zur Laufzeit geprüft werden.
Prinzip: turning runtime errors into compile time errors.
Zusätzlich natürlich das Cast-Thema, zB. bei Rückgaben des Eingangsparameters bei solchen Methoden.
Interface Methode(Interface x) {}
vs
T Methode<T>(T x) where T: Interface {}
Generics sind einfach enorm wichtige Bausteine in der Software Architektur von .NET. Sie bieten eine viel höhere Erweiterbarkeit.
Bei der Generic Variante bekomme ich den konkreten Typ zurück - beim Interface nicht.
Dann noch einfache Fakten, die mit meiner eigentlichen Intension von "Besser" nichts zutun hatten:
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Mir ist klar, daß Generics einen Vorteil bilden können (gerade bei Factory-Methoden, welche einen konkreten Typ zurückgeben), in dem konkreten Fall
public void TuWasMitDerKlasse(IIrgendwas klasseDieInterfaceImplementiert)
jedoch ist das eine typische Signatur von Dependency Injection Methoden (u.a. auch Konstruktoren) - und daher bin ich irritiert, wenn dies dann immer durch Generics ersetzt werden sollte.
Können wir uns darauf einigen, daß ein Entwickler beide Varianten kennen sollte und je nach Anwendungsfall (also z.B. wenn mehr als eine Constraint-Bedingung vorliegt) dann Generics bevorzugen sollte?
und daher bin ich irritiert, wenn dies dann immer durch Generics ersetzt werden sollte.
Hat ja auch keiner gesagt.
Die Diskussion hat sich auch von meiner eigentlichen, spezifischen Aussage und dessen Hintergrund total verrannt; in meinen Augen - trotz mehrfacher Hinweise - weil man offenbar die Wirkung von Generics nicht bewusst ist und den Sinn nicht verstanden hat.
Daher bin ich auch raus.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Hallo CrocodileDundee,
war denn für dich schon etwas brauchbares dabei? Nur um mal zum Kern des Problems zurück zu kehren.
Wissen ist nicht alles. Man muss es auch anwenden können.
PS Fritz!Box API - TR-064 Schnittstelle | PS EventLogManager |