Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi typisierte Konstante definieren: const C: array [...] of TGUID = (...); (https://www.delphipraxis.net/169850-typisierte-konstante-definieren-const-c-array-%5B-%5D-tguid-%3D-%3B.html)

Panthrax 16. Aug 2012 08:10

Delphi-Version: 2010

typisierte Konstante definieren: const C: array [...] of TGUID = (...);
 
Delphi-Quellcode:
type
  ISchnittstelle = interface
  end;

//  TSchnittstelleClass = class of ISchnittstelle; {1}
//  TSchnittstelleClass = interface of ISchnittstelle; {2}

  IEins = interface(ISchnittstelle)
    ['{3E88C3A1-8791-45C2-961D-41423855E863}']
  end;

  IZwei = interface(ISchnittstelle)
    ['{ED86F176-8E55-43BC-8BB2-8FAEB9E52D29}']
  end;

  TFormat = (ftEins, ftZwei);
{1} [DCC Fehler]: E2021 Klassentyp erwartet
{2} Gibt es nicht.


Ich möchte nun eine Konstante dieser Art definieren:

Versuch 1:
Delphi-Quellcode:
const
  Schnittstellen: array [TFormat] of TGUID = (
    IEins{3}, IZwei
  );
{3} [DCC Fehler]: E2010 Inkompatible Typen: 'TGUID' und 'AnsiString'

Versuch 2:
Delphi-Quellcode:
const
  Schnittstellen: array [TFormat] of AnsiString = (
    IEins{4}, IZwei
  );
{4} [DCC Fehler]: E2010 Inkompatible Typen: 'AnsiString' und 'TGUID'

Alternativ ist es möglich eine Variable zu deklarieren und sie dann im Quelltext zu füllen. Mir geht es aber ausdrücklich um eine Konstante. Wie geht's?

Furtbichler 16. Aug 2012 08:44

AW: typisierte Konstante definieren: const C: array [...] of TGUID = (...);
 
Was ist der Unterschied zwischen den Datentypen TGUID, String, Interfacedeklaration und Interface?

Du kannst imho keine Konstantendeklaration eines Interfaces (bzw. einer Instanz) vornehmen.

Deklariere das Array als global und erzeuge die Instanzen im Initialisierungsabschnitt deiner Unit. Wenn Du global=böse setzt, dann bastel dir eine statische Klasse, die das Array als Klassenvariable deklariert, kommt aber aufs gleiche raus.

Panthrax 16. Aug 2012 10:14

AW: typisierte Konstante definieren: const C: array [...] of TGUID = (...);
 
Ein Schnittstellentyp ein Typ, und damit keine Instanz. Ich hätte gern die Schnittstellentypen ähnlich herumgereicht, wie das bei Klassentypen geht (bspw. so:
Delphi-Quellcode:
TFormatSchnittstelle = interface of IFormat;
Delphi-Quellcode:
Formate: array [TFormat] of TFormatSchnittstelle = (IEins, IZwei);
). Leider scheint es, dass es einen solchen Typ nicht gibt. In diesem Fall hier zählt letztendlich, dass die Schnittstellenidentifikation, die GUID, verfügbar ist, die man
Delphi-Quellcode:
Supports
übergeben kann:
Delphi-Quellcode:
Supports(Daten, Formate[F], Format)
. Aber auch dafür scheint es keinen Typ zu geben, den man in einer Konstantendefinition verwenden könnte. Für eine Variable gibt es einen solchen Typ:
Delphi-Quellcode:
type
  TFormate = array [TFormat] of TGUID;
const
  Konstante: TFormate = (IEins, IZwei); {3}
var
  Variable: TFormate; { funktioniert }
begin
  Variable[ftEins] := IEins;
  Variable[ftZwei] := IZwei;
end;
{3} [DCC Fehler]: E2010 Inkompatible Typen: 'TGUID' und 'AnsiString' (wie im ersten Beitrag)

Ich hätte gern eine Konstante, damit der Kompiler darauf hinweist, dass die Zuordnung anpasst werden muss, wenn sich die Anzahl der Formate ändert.

NormanNG 16. Aug 2012 11:12

AW: typisierte Konstante definieren: const C: array [...] of TGUID = (...);
 
Hi,

{3} ist nicht sehr komfortabel, geht aber:

Delphi-Quellcode:
type
  TFormate = array [TFormat] of TGUID;
const
  Konstante: TFormate = ('{3E88C3A1-8791-45C2-961D-41423855E863}', '{ED86F176-8E55-43BC-8BB2-8FAEB9E52D29}'); {3}
var
  Variable: TFormate; { funktioniert }
begin
  Variable[ftEins] := IEins;
  Variable[ftZwei] := IZwei;
end;

Furtbichler 16. Aug 2012 12:36

AW: typisierte Konstante definieren: const C: array [...] of TGUID = (...);
 
Ich verwende dafür eine Interfacefactory, analog zu einer Classfactory.
Dahinter verbirgt sich einfach eine TInterfaceList, die in der Unit Cntnrs zu finden ist.

NormanNG 16. Aug 2012 12:50

AW: typisierte Konstante definieren: const C: array [...] of TGUID = (...);
 
Zitat:

Ich verwende dafür eine Interfacefactory, analog zu einer Classfactory.
Dahinter verbirgt sich einfach eine TInterfaceList, die in der Unit Cntnrs zu finden ist.
Bekommst du damit auch ggf. Fehlermeldungen beim Kompilern :gruebel:

Panthrax 16. Aug 2012 15:24

AW: typisierte Konstante definieren: const C: array [...] of TGUID = (...);
 
So wird es werden:
Delphi-Quellcode:
const
  EinsGUID = '{3E88C3A1-8791-45C2-961D-41423855E863}';
  ZweiGUID = '{ED86F176-8E55-43BC-8BB2-8FAEB9E52D29}';

type
  IFormat = interface
    { ... }
  end;

  IEins = interface(IFormat)
    [EinsGUID]
  end;

  IZwei = interface(IFormat)
    [ZweiGUID]
  end;

type
  TFormat = (ftEins, ftZwei);
const
  Formate: array [TFormat] of TGUID = (
    EinsGUID, ZweiGUID
  );
Für die GUIDs separate Konstanten zu definieren ist ein Kompromiss, der es ermöglicht, dass keine Zuordnungen verlorengehen und jede Information nur einmal angegeben wird. Schade, dass man nicht direkt die Schnittstellentypbezeichner nehmen kann - bei Variablen geht es ja...

Vielen Dank an Euch beide!

Furtbichler 16. Aug 2012 16:00

AW: typisierte Konstante definieren: const C: array [...] of TGUID = (...);
 
Zitat:

Zitat von NormanNG (Beitrag 1178475)
Zitat:

Ich verwende dafür eine Interfacefactory, analog zu einer Classfactory.
Dahinter verbirgt sich einfach eine TInterfaceList, die in der Unit Cntnrs zu finden ist.
Bekommst du damit auch ggf. Fehlermeldungen beim Kompilern :gruebel:

Nein, aber ich löse damit das Problem und kann zudem jederzeit diese Liste aka Factory erweitern. Ich probiere also nicht ewig an einer statischen Konstantendeklaration, sondern bin effizient.

@Panthrax: Respekt für deine Ausdauer. Ich nehme dafür eine vorgefertigte Factoryklasse (aber das erwähnte ich ja bereits).

Panthrax 17. Aug 2012 13:33

AW: typisierte Konstante definieren: const C: array [...] of TGUID = (...);
 
Ich kann den architektonischen Ansatz verstehen. Vielen Dank für den Hinweis! Im größeren Stil würde ich ihn auch einsetzen, nicht aber in diesem kleinen Fall. Wenn man also eine "(parametrisierte) Fabrik" hier erkennen möchte, dann ist sie auf eine Zuordnung reduziert zwischen einem programmexternen Wert
Delphi-Quellcode:
var F: TFormat
und einer Schnittstelle
Delphi-Quellcode:
var Schnittstelle: interface of IFormat
. Weil es letzteren Typ nicht gibt und Delphi an dieser Stelle den Schnittstellentypbezeichner nicht als Schnittstellentypidentifikation zulässt, wird letztere eben als GUID
Delphi-Quellcode:
const SchnittstelleGUID {: TGUID} = '...';
zugeordnet:
Delphi-Quellcode:
const Formate: array[TFormat] of TGUID = (SchnittstelleGUID);
Damit kann ich von einer Instanz
Delphi-Quellcode:
var Instanz: IInterface
erfragen, ob sie ein bestimmtes Format
Delphi-Quellcode:
var Format: IFormat
untersützt:
Delphi-Quellcode:
if Supports(Instanz, Formate[F], Format) then...
Der weitere Ablauf ist dann unabhängig vom tatsächlichen Format.

Aber warum eine Konstante? * Die Formate ändern sich nicht in der Lebenszeit einer Programmversion. * Es sind Daten, nicht Anweisungen. * Weil es nur eine handvoll Werte sind und es kein riesiges Konstrukt ist, ist die Notation leicht (leichter) zugänglich (als mit einer verwaltenden Klasse). * Die Zuordnung kann dort angebracht werden, wo auch die Formate definiert sind -- bei
Delphi-Quellcode:
type TFormat
. * Es ist nicht perfekt, aber wenn sich die Anzahl der Formate zukünftig ändert, wird beim Kompilieren schon gemerkt, dass die Zuordnung nicht mehr passt. Frühes Fehlerfinden bedeutet fast immer auch geringere Kosten.

Ich wollte die Verbindungen zwischen Schnittstelle (und, wegen des Kompromisses, ihrer GUID) und dem externen Wert nicht verlieren. Denn ich glaube, dass jede Information nur ein einziges Mal notiert werden sollte. Das zwingt zwar einerseits zu sehr starker Formalisierung und Abstraktion, was merklichen Aufwand macht, aber auch zu kürzeren Programmen führt (Skaleneffekt). Das verringert entsprechend auch den Testaufwand, denn es sind weniger Quelltextzeilen zu testen. Zudem kann man sich sicher sein: Wenn man einmal ändern muss, gibt es eine (einzige) Stelle, das zu tun. Keine quälenden Gewissensbisse "Habe ich jetzt alles...?", was ich gedanklich sehr befreiend finde.

Das war nun ziemlich weit ausgeholt und vieles auch nur angerissen. Fabriken haben ihre Berechtigung, ich setze sie selbst ein. Aber ich hoffe, dass ich meine Sicht ein wenig klarer machen konnte. Vielleicht nutzt es Dir oder den Mitlesern an anderer Stelle.


Alle Zeitangaben in WEZ +1. Es ist jetzt 16:21 Uhr.

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