Laden...

Wie kann ich eine Klasse als Methoden-Parameter in Methode übergeben?

Erstellt von CrocodileDundee vor 4 Jahren Letzter Beitrag vor 4 Jahren 1.845 Views
C
CrocodileDundee Themenstarter:in
51 Beiträge seit 2018
vor 4 Jahren
Wie kann ich eine Klasse als Methoden-Parameter in Methode übergeben?

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

656 Beiträge seit 2008
vor 4 Jahren

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.

2.298 Beiträge seit 2010
vor 4 Jahren

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 |

4.931 Beiträge seit 2008
vor 4 Jahren

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)?!

2.207 Beiträge seit 2011
vor 4 Jahren

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

16.806 Beiträge seit 2008
vor 4 Jahren

Im Fall des Interfaces wäre aber das besser

public void TuWasMitDerKlasse<T>(T klasseDieInterfaceImplementiert) where T: class, IIrgendwas
P
64 Beiträge seit 2011
vor 4 Jahren

Huhu, das ist keine ketzerische Frage sondern ernst gemeint. Warum das als generic übergeben?

16.806 Beiträge seit 2008
vor 4 Jahren

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.

P
64 Beiträge seit 2011
vor 4 Jahren

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

16.806 Beiträge seit 2008
vor 4 Jahren

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 😉

P
64 Beiträge seit 2011
vor 4 Jahren

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

16.806 Beiträge seit 2008
vor 4 Jahren

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 😃

P
64 Beiträge seit 2011
vor 4 Jahren

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).

16.806 Beiträge seit 2008
vor 4 Jahren

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.

4.931 Beiträge seit 2008
vor 4 Jahren

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?

3.170 Beiträge seit 2006
vor 4 Jahren

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

4.931 Beiträge seit 2008
vor 4 Jahren

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.

16.806 Beiträge seit 2008
vor 4 Jahren

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:

  • Ich kann Klassen bzw. Erweiterungsmethoden ganz anders und optimaler gestalten
  • (Achtung Micro-Optimierung): Der Aufruf des Generic ist i.d.R. schneller als über das Interface. Gibts zig Benchmarks und Artikel zu.
  • Thema Boxing bei Value Types
  • Der generische Weg gilt seit langem auch in vielen Büchern als "idiomatic"
4.931 Beiträge seit 2008
vor 4 Jahren

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?

16.806 Beiträge seit 2008
vor 4 Jahren

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.

2.298 Beiträge seit 2010
vor 4 Jahren

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 |