2009-04-15 15 views
3

Ich habe eine Prozedur, die einen Parameter vom Typ TObject, so etwas wie dies erwartet:Delphi: Pass TObject in Array von Varianten

MyProcedure (const AValue : TObject); 

ich ein Array von Variant haben, dass ich Schleife durch die Prozedur aufzurufen , so etwas wie dieses:

for i:=0 to High(myArray) do 
    MyProcedure (myArray[i]); 

Der Compiler gibt eine Fehlermeldung, "Inkompatible Typen: TObject und Variant".

Was kann ich tun, um dies zu umgehen?

Weitere Informationen: Bis jetzt habe ich einfache Typen (Strings, Zahlen, Datumsangaben) in Variantenarrays übergeben (die Arrays sind typischerweise eine Mischung aus verschiedenen Typen - ich übergebe sie schließlich als Parameter an eine gespeicherte Datenbankprozedur). Jetzt muss ich (in bestimmten Fällen) auch ein TObject übergeben.

Welcher Datentyp/Struktur ist am besten geeignet, um die Werte zu übergeben, die sowohl einfache Typen als auch Objekte enthalten können? Ich denke, ich könnte meinen eigenen TParam-Typ erstellen, der ein Feld für beide hat, aber ich bin mir nicht sicher über die genaue Syntax. Hat jemand ein Beispiel dafür?

+0

Verwandte: http://StackOverflow.com/Questions/366329/Why-Cant-delphi-Variants-Hold-Objects –

Antwort

8

Eine Variante kann keine Objekte enthalten, sie kann nur primitive Typen wie Integer und String enthalten.

Ich würde vorschlagen, Ihr Array zu ändern, um von dem Typ zu sein, den Sie lieber als Variante wünschen. Wenn Sie sich des gewünschten Objekttyps nicht sicher sind, erstellen Sie ein Array von TObject oder die niedrigstmögliche Basisklasse der Objekte, die Ihr Array enthalten soll.

+0

Die benutzerdefinierten Varianten von Delphi (TCustomVariantType-Nachkommen) können Objekte enthalten. Es gibt sogar Beispiele dafür in der VCL, siehe SqlTimSt.TSQLTimeStampVariantType, FMTBcd.TFMTBcdVariantType. –

1

Meine erste Reaktion ist zu fragen, warum Sie TObjects in einer Liste von Varianten speichern, aber vorausgesetzt, Sie haben einen guten Grund!

Wenn Sie es geschafft haben, Ihre TObject-Instanz an erster Stelle in das Array zu platzieren, dann haben Sie wahrscheinlich den Zeiger auf das Objekt gesetzt. In diesem Fall, was Sie tun müssen, ist den Variant/Integer als TObject zB typisiert

for i:=0 to High(myArray) do 
    MyProcedure (TObject(myArray[i])); 

Dies sollte funktionieren, aber wie bei jedem typecasting es bis zu Ihnen, um sicherzustellen, dass arr [i] ist eigentlich ein Zeiger zu einer TObject-Instanz oder schreckliche Dinge passieren könnten.

Sind Sie sicher, dass ein TList nicht tun würde, was Sie wollen. Eine Variante ist eigentlich gedacht, um fundamentale Typen wie string, integer, float, boolean nicht Objects zu speichern.

3

Sie können keine einfachen Objekte als Variante speichern. Aber Sie können Schnittstellen speichern.

var 
    v : Variant; 
    i : IInterface; 

begin 
    v := i; // Works perfectly; 
end. 

Schauen Sie sich die Typen für die Variante:

varEmpty = $0000; { vt_empty  0 } 
varNull  = $0001; { vt_null   1 } 
varSmallint = $0002; { vt_i2   2 } 
varInteger = $0003; { vt_i4   3 } 
varSingle = $0004; { vt_r4   4 } 
varDouble = $0005; { vt_r8   5 } 
varCurrency = $0006; { vt_cy   6 } 
varDate  = $0007; { vt_date   7 } 
varOleStr = $0008; { vt_bstr   8 } 
varDispatch = $0009; { vt_dispatch  9 } 
varError = $000A; { vt_error  10 } 
varBoolean = $000B; { vt_bool  11 } 
varVariant = $000C; { vt_variant  12 } 
varUnknown = $000D; { vt_unknown  13 } 
//varDecimal = $000E; { vt_decimal  14 } {UNSUPPORTED as of v6.x code base} 
//varUndef0F = $000F; { undefined  15 } {UNSUPPORTED per Microsoft} 
varShortInt = $0010; { vt_i1   16 } 
varByte  = $0011; { vt_ui1   17 } 
varWord  = $0012; { vt_ui2   18 } 
varLongWord = $0013; { vt_ui4   19 } 
varInt64 = $0014; { vt_i8   20 } 
varUInt64 = $0015; { vt_ui8   21 } 

Sie können, wenn Sie wirklich wollen, werfen TObject zu Integer auf Zeiger und speichern. Aber ich bin mir nicht sicher, ob du das wirklich willst.

+0

Ich stimme mit GameCat überein, wenn Sie Objekte als Varianten übergeben müssen, dann würde ich eine Schnittstelle verwenden . – skamradt

0

Ich denke nicht, dass es eine gute Idee ist, ein TParam mit einer Variant-Variablen eine TOBject-Variable zu erstellen. Etwas wie:

Tobject = record 
    prim: Variant; 
    obj: TObject; 
end 

Würde funktionieren, aber es scheint mir sehr chaotisch. Pascal ist keine dyanisch typisierte Sprache und ich würde es nicht als eine Art behandeln.Ich würde vorschlagen, entweder:

eine andere Funktion erstellen zu Variant zu behandeln, so wie auch mit

MyProcedure (const AValue : TObject); 

haben auch

MyProcedure (const AValue : Variant); 

und Ihre Daten separat behandeln. Oder einen Datensatz erstellen, die Ihre Dateneingänge definiert, zum Beispiel, anstelle von TParam von Variante und Objekt hat so etwas wie:

TStoredProcParm = record 
    name: String; 
    bought: TDateTime; 
end; 

und so weiter. Vielleicht haben Sie so viele verschiedene Daten, dass die Variante/Objektroute die beste ist, aber es scheint ein bisschen ein Maintenance-Kopfschmerz zu sein - wenn Ihr anderer Code ein Array von Variant passiert, wissen Sie, welche Variante welche ist und wie Sie sie verwenden von ihnen in Ihrem Stored proc?

+0

Ich sehe Ihren Punkt über den TParam-Datensatz, der "chaotisch" ist. Aber ich habe eine Möglichkeit zu wissen, wann ich welches verwenden soll, also ist dies wahrscheinlich die beste Lösung für mich in diesem Projekt (der TObject-Wert wird sehr selten verwendet). – ObiWanKenobi