Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   C# Typen / Klassen als Parameter verwenden (https://www.delphipraxis.net/153949-typen-klassen-als-parameter-verwenden.html)

Meflin 22. Aug 2010 11:25

Typen / Klassen als Parameter verwenden
 
Moin,

in Smalltalk kann ich sowas machen:
Code:
classes := {ClassA. ClassB. ClassC}.
classes do: [:each |
    each register]
(Ja, es geht hierbei um Klassen, nicht Instanzen / Exemplare von Klassen).

In Delphi sollte derartiges ja über das class of Konstrukt auch möglich sein. Ich bräuchte allerdings ein praktikables Äquivalent in C# und da konnte ich bis jetzt nichts finden.

Ein weiterer netter Anwendungsfall wäre dann
Code:
void foo(ASuperClass c) {
    bar = new c()
}

implementation 22. Aug 2010 11:59

AW: Typen / Klassen als Parameter verwenden
 
Ein solches Konstrukt gibt es in C# nicht. Habe ich auch schon vergeblich nach gesucht :?
Es ließe sich aber evtl. durch Generics lösen:
Code:
void foo<T>() where T: BasisKlasse, new()
{
  bar = new T();
}
// ...
foo<BasisKlasse>();
foo<AbgeleiteteKlasse>();
Dann muss die übergebene Klasse aber auch einen Konstruktor mit 0 Argumenten besitzen.

Meflin 22. Aug 2010 13:34

AW: Typen / Klassen als Parameter verwenden
 
Zitat:

Zitat von implementation (Beitrag 1044083)
Ein solches Konstrukt gibt es in C# nicht. Habe ich auch schon vergeblich nach gesucht :?

Verdammt, das ist schade :(

für das zweite Beispiel sollte das mit den Generics ausreichend sein, wenn es klappt. Für den ersten hilft das allerdings auch nichts :stupid:

Medium 22. Aug 2010 16:23

AW: Typen / Klassen als Parameter verwenden
 
Schau dir mal den Namespace System.Type an, und den Operator typeof().

implementation 22. Aug 2010 16:45

AW: Typen / Klassen als Parameter verwenden
 
Heißt das Namespace nicht System.Reflection? :stupid:
Das ist aber eigentlich auch keine Entsprechung für class-of, sondern für die RTTI...
Aber damit sollte sich das erste Beispiel bewältigen lassen.

Meflin 22. Aug 2010 17:18

AW: Typen / Klassen als Parameter verwenden
 
Zitat:

Zitat von implementation (Beitrag 1044147)
Aber damit sollte sich das erste Beispiel bewältigen lassen.

Naja nicht ganz. Zwar kann man damit sowas anlegen:
Code:
Type[] KnownClasses = new Type[] { typeof(ClassA), typeof(ClassB) };
Aber wie komme ich nun vom Type wieder zur Klasse? Ein Eintrag aus dem Array kennt ja nun logischerweise die (statischen) Methoden meiner Klassen nicht (ist ja auch vom Typ Type) und ein cast ist nicht möglich :(
Code:
foreach (Type t in KnownClasses) {
    // ? t.foo()
}

implementation 22. Aug 2010 17:24

AW: Typen / Klassen als Parameter verwenden
 
Die Lösung ist eine Methode von System.Type, nämlich InvokeMember :wink:

Khabarakh 22. Aug 2010 17:28

AW: Typen / Klassen als Parameter verwenden
 
Ich denke, ein konkretes Anwendungsbeispiel wäre langsam hilfreich :) . Von Dependency Injection bis zu Funktionaler Programmierung (Higher-Order-Functions) gibt es manchmal sogar bessere Lösungen als virtuelle statische Methoden.

Eine virtuelle statische Methode direkt umzusetzen, ohne Verlust von statischer Typisierung, wirst du aber nur erreichen, indem du sie zur Instanzmethode machst und dafür ggf. in eine eigene Klasse auslagerst.

implementation 22. Aug 2010 17:35

AW: Typen / Klassen als Parameter verwenden
 
Zitat:

Zitat von Khabarakh (Beitrag 1044164)
Von Dependency Injection bis zu Funktionaler Programmierung (Higher-Order-Functions) gibt es manchmal sogar bessere Lösungen als virtuelle statische Methoden.

In C# gibt es nicht einmal virtuelle statische Methoden :wink:
Daher ist das erste Beispiel sowieso Schwachsinn.
Da müsste Microsoft erstmal Delphi's Klassenmethoden abgucken.:lol:

Meflin 22. Aug 2010 17:38

AW: Typen / Klassen als Parameter verwenden
 
Zitat:

Zitat von Khabarakh (Beitrag 1044164)
Ich denke, ein konkretes Anwendungsbeispiel wäre langsam hilfreich :) .

Nungut... es soll eine Reihe von "Events" verwaltet werden... Im Endeffekt Daten, die über einen Socket empfangen werden. Für jeden möglichen Befehl gibt es eine Unterklasse von
Code:
    abstract class ServerEvent
    {
        public static string command() {
            return "";
        }

        public static void handler() { } 
    }
Alle bekannten Events sollen nun bei einem Dispatcher registriert werden (der ServerEvent.Command aus den TCP Daten liest und dann ServerEvent.handler() passend aufruft).

Mit der im Eingangspost gezeigten Smalltalk-Variante wäre ich da voll zufrieden :stupid:

Vermutlich gibt es dafür auch völlig andere Lösungsansätze; sollte meine Idee tatsächlich nur schwer umsetzbar sein, werde ich wohl auch umstellen...

Khabarakh 22. Aug 2010 18:00

AW: Typen / Klassen als Parameter verwenden
 
Nicht so kompliziert denken und einfach Instanzmethoden daraus machen ;) ? Ich sehe da keinen Nachteil - und wie gesagt können sich dadurch sogar ganz andere Möglichkeiten eröffnen :) :
Code:
   class Dispatcher
   {
      [ImportMany]
      IEnumerable<ServerEvent> EventHandlers { get; set; }

      public Dispatcher()
      {
         // Here be MEF magic...
         var catalog = new DirectoryCatalog(@".\");
         var container = new CompositionContainer(catalog);
         container.Composeparts(this);
      }

      void Receive()
      {
         ServerEvent handler = EventHandlers.First(h => h.Command == command);
         handler.Handle();
      }
   }

   public abstract class ServerEvent
   {
      public virtual string Command { get { return ""; } }
      public void Handle();
   }

   [Export(ServerEvent)]
   class IAmATeapotServerEvent : ServerEvent { ... }
Wirf eine weitere Assembly mit einer ServerEvent-Ableitung in den bin-Ordner und MEF wird sie ohne weiteres Zutun ebenfalls dem Dispatcher zuordnen. Und jetzt sag mir, dass das mit statischen virtuellen Methoden eleganter lösbar sei :) .

Meflin 22. Aug 2010 23:45

AW: Typen / Klassen als Parameter verwenden
 
Das klingt natürlich wirklich nett. Einen Haken hat das ganze allerdings: das gibts alles erst ab .Net 4 oder? Ich bin aber an 3.5 gebunden, durch andere Libraries...

Zitat:

Zitat von Khabarakh (Beitrag 1044177)
Nicht so kompliziert denken und einfach Instanzmethoden daraus machen ;) ? Ich sehe da keinen Nachteil - und wie gesagt können sich dadurch sogar ganz andere Möglichkeiten eröffnen :)

Ist ja nicht so dass ich was gegen Instanzen hätte :stupid: Nur bei meinem Ansatz wären sie einfach überflüssig gewesen...

Phoenix 23. Aug 2010 07:21

AW: Typen / Klassen als Parameter verwenden
 
Du kannst doch einfach per reflection hergehen, die statischen Methode ermitteln und aufrufen.
Um die Typen zu finden die diese Methode implementieren kannst du im Prinzip hergehen und mittels linq abfragen, welche typen eine statische Methode dieses namens haben. Das ist aber nicht gerade Performant, weil die Abfrage alle typen nach der Methode abfragt.

Meflin 23. Aug 2010 12:18

AW: Typen / Klassen als Parameter verwenden
 
Zitat:

Zitat von Phoenix (Beitrag 1044269)
Du kannst doch einfach per reflection hergehen, die statischen Methode ermitteln und aufrufen.

Naja gehen täte das sicherlich. Aber hübsch finde ich das nun auch nicht gerade.

Mal gucken ob ich nicht doch auf 4 umsteigen kann...

Phoenix 23. Aug 2010 15:37

AW: Typen / Klassen als Parameter verwenden
 
Hast Du Einfluss auf die Klassen die Du da verwendest? Kannst Du die z.B. mit einem Custom Attribut versehen oder von einem bestimmten Interface ableiten (ich weiss, bei statischen Methoden ist das eher Sinnlos, aber z.B. INamingContainer ist auch nur ein flagging interface das keine Methoden oder Properties vorgibt).

Das macht dann das Ermitteln der entsprechenden Typen ziemlich einfach.

Ps: Ich erwähne jetzt nur am Rande das Prism virtuelle statische Methoden schon länger unterstützt: http://prismwiki.embarcadero.com/en/Class_References ...

Meflin 23. Aug 2010 18:49

AW: Typen / Klassen als Parameter verwenden
 
Zitat:

Zitat von Phoenix (Beitrag 1044378)
Hast Du Einfluss auf die Klassen die Du da verwendest? Kannst Du die z.B. mit einem Custom Attribut versehen oder von einem bestimmten Interface ableiten (ich weiss, bei statischen Methoden ist das eher Sinnlos, aber z.B. INamingContainer ist auch nur ein flagging interface das keine Methoden oder Properties vorgibt).

Die Klassen stammen allesamt von mir - ich kann da also machen was ich will :-D

Wie sich das nun auswirkt, verstehe ich allerdings nicht, denn von Reflection in C# habe ich ehrlichgesagt null Ahnung ;)

Phoenix 23. Aug 2010 19:11

AW: Typen / Klassen als Parameter verwenden
 
Du kannst sowas machen:

Code:
var results = from type in someAssembly.GetTypes()
              where typeof(IFoo).IsAssignableFrom(type)
              select type;
Du hast in results dann eine Liste aller Typen, die Dein Flagging interface haben.
Der Aufruf sieht dann in etwa so aus:

Code:
var t := results.First();
foreach (MethodInfo mi in t.GetMethods(BindingFlags.Static |
BindingFlags.Public))
{
  Console.WriteLine("method {0}", mi.Name);
  mi.Invoke(null, null); // parameter entsprechend setzen.
}

Khabarakh 23. Aug 2010 20:16

AW: Typen / Klassen als Parameter verwenden
 
Zitat:

Zitat von Meflin (Beitrag 1044259)
Das klingt natürlich wirklich nett. Einen Haken hat das ganze allerdings: das gibts alles erst ab .Net 4 oder?

Integriert ja, ansonsten... :) . Wenn du darin Overkill siehst, kann ich dir das aber schlecht verübeln, also würde ich in Anlehnung an Phoenix' Code den MEF-Composition-Teil durch
Code:
EventHandlers = Assembly.GetEntryAssembly().GetTypes().Where(t => t.IsSubclassOf(typeof(ServerEvent))).ToList();
ersetzen.
Zitat:

Zitat von Meflin (Beitrag 1044259)
Ich bin aber an 3.5 gebunden, durch andere Libraries...

Hm? Wenn du einen Breaking Change in 4.0 treffen solltest, gebe ich dir einen aus ;) .

Zitat:

Zitat von Meflin (Beitrag 1044259)
Ist ja nicht so dass ich was gegen Instanzen hätte :stupid: Nur bei meinem Ansatz wären sie einfach überflüssig gewesen...

Und Herr Hejlsberg dachte wahrscheinlich umgekehrt, dass ein Feature überflüssig ist, das sich (zumindest in Fällen wie diesem) ohne wirklichen Verlust auch auf einfacherem Weg realisieren lässt. Wie Eric Lippert es einmal sagte: Jedes Sprachfeature beginnt bei -500...
Und ohne dir nahe treten zu wollen, oder überhaupt zu wissen, wie tief du schon in der CLR drinsteckst, ist es imo ein beeinträchtigender Fehler von Umsteigern, in einer managed Sprache Instanzierungen zählen zu wollen. Sagt mir jedenfalls meine eigene Erfahrung - man muss loslassen können, um zu genießen :stupid: .

@Sebastian: Uh, jetzt musst du mir aber dringend erklären, wo du nun noch einen Vorteil von statischen Methoden + Reflection siehst.

Meflin 23. Aug 2010 21:25

AW: Typen / Klassen als Parameter verwenden
 
Zitat:

Zitat von Khabarakh (Beitrag 1044439)
Und ohne dir nahe treten zu wollen, oder überhaupt zu wissen, wie tief du schon in der CLR drinsteckst...

Nur um mit einem kurzen Einwurf diese Frage zu beantworten: garnicht ;)

Meflin 30. Aug 2010 16:54

AW: Typen / Klassen als Parameter verwenden
 
Zitat:

Zitat von Khabarakh (Beitrag 1044177)
Code:
   class Dispatcher
   {
      [ImportMany]
      IEnumerable<ServerEvent> EventHandlers { get; set; }

      public Dispatcher()
      {
         // Here be MEF magic...
         var catalog = new DirectoryCatalog(@".\");
         var container = new CompositionContainer(catalog);
         container.Composeparts(this);
      }

      void Receive()
      {
         ServerEvent handler = EventHandlers.First(h => h.Command == command);
         handler.Handle();
      }
   }

   public abstract class ServerEvent
   {
      public virtual string Command { get { return ""; } }
      public void Handle();
   }

   [Export(ServerEvent)]
   class IAmATeapotServerEvent : ServerEvent { ... }

Also beim Versuch der Umsetzung dieser durchaus reizvollen Lösungsidee bin ich jetzt leider doch noch auf Probleme gestoßen.
Code:
[Export(ServerEvent)]
wird bei mir nicht zugelassen mit Fehler Verwendung eines Typen wie Variable etc... Ich hab ees dann hauptsächlich so versucht:
Code:
[Export(typeof(ServerEvent))]
[ImportMany(typeof(ServerEvent))]
da wird dann allerdings außer der abstrakten Basisklasse garnichts importiert. So wurde das ganze allerdings in den Beispielcodes die ich gefunden habe angewendet :gruebel:

Ich bitte um Erleuchtung :stupid:

implementation 30. Aug 2010 17:03

AW: Typen / Klassen als Parameter verwenden
 
Das
Code:
[Export(typeof(ServerEvent))]
muss auch bei allen anderen Events sein, auch wenn es sich um Kindklassen von ServerEvent handelt:
Code:
// wird exportiert ...
[Export(typeof(ServerEvent))]
class ServerEvent
{
  ..
}
// wird ebenfalls exportiert ...
[Export(typeof(ServerEvent))]
class DummyEvent : ServerEvent
{
  ...
}
// wird nicht exportiert ...
// trotz der Vererbung von ServerEvent
class WuppdiEvent : ServerEvent
{

}

Meflin 30. Aug 2010 17:25

AW: Typen / Klassen als Parameter verwenden
 
Zitat:

Zitat von implementation (Beitrag 1046135)
muss auch bei allen anderen Events sein, auch wenn es sich um Kindklassen von ServerEvent handelt

Habe ich (genauergesagt ja nur bei diesen, bei der Basisklasse habe ich kein Export stehen).

Khabarakh 30. Aug 2010 20:10

AW: Typen / Klassen als Parameter verwenden
 
Da rächt es sich, dass ich MEF noch nie verwendet habe :stupid: .
Code:
var catalog = new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly());
funktioniert. Vielleicht ignoriert der DirectoryCatalog Exe-Assemblies.

(Die nächsten 10 Tage im Urlaub...)

Meflin 30. Aug 2010 20:14

AW: Typen / Klassen als Parameter verwenden
 
Zitat:

Zitat von Khabarakh (Beitrag 1046163)
Vielleicht ignoriert der DirectoryCatalog Exe-Assemblies.

Könnte sein. In der Liste stehen jedenfalls nur dlls. Es gibt da aber auch eine Filterproperty, mal gucken ob ich da noch ein bisschen rumprobiere ;-)

Deine neue Lösung funktioniert jedenfalls wunderbar :thumb:


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:54 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz