Salvador
Salvador

Reputation: 16472

Managing null values in variants using Delphi

I'm working with a COM component which exposes a lot of Variant properties, but sometimes these values are null. When I try to convert these values to string (or another Delphi type) the application raises an exception like this:

Could not convert variant of type (Null) into type (String)

But if I use .net to call the same properties and the values are null, no exceptions are raised and the null values are treated as empty strings.

My question there is a way to handle these null values from Delphi avoiding these exceptions?

Thanks in advance.

Upvotes: 18

Views: 42022

Answers (5)

Remy Lebeau
Remy Lebeau

Reputation: 595971

VarToStr() and VarToStrDef() are the correct and proper way to convert a Null Variant to a String, as they explicitially check for Null values internally.

Upvotes: 9

hola
hola

Reputation: 71

..from user422039 code use VarToStr otherwise S:=V relays on an implicit conversion which may create different result on different environment:

S := VarToStr(V);
or
S := VarToStrDef(V, yourdefaultvalue);

Upvotes: 4

Warren  P
Warren P

Reputation: 68892

The accepted answer changes a global setting, and could have unintended side effects on the operation of other code that was working before you changed it.

First you could just use VarToStrDef, secondly, if you must provide some functionality other than that, then I would have my code call my own function MyVarToStr, and do it like this:

resourcestring
    SNilValue = '[nil]';


function VarIsAssigned(v:Variant):Boolean; inline;
begin
          result := (v<>Variants.Null) and (not VarIsNull(V));
end;


function MyVarToStr( v:Variant):String;
begin
  if VarIsAssigned(v) then
    result := VarToStr(v)
else
    result := SNilValue;
end;

Since it seems that VarToStrDef should be enough, I only mean to demonstrate that it's better to write your code and call your own code, than to try to "globally change" the default behaviour of VCL/RTL library code.

Upvotes: 21

user422039
user422039

Reputation: 1458

This is a documented behaviour of VarToStr function. There is no need to reinvent a wheel.

Null variant is distinct type (yes, it is a type, not merely a value), which denotes either missing or unknown data. So, strictly speaking, regular variant dynamic-typing should not happen with Null values (illustrated and reflected in RTL defaults).

given:

var
  V: Variant;
  S: string;

better code

S := VarToStr(V);             { stongly-typed explicit conversion }

relatively good code

if not VarIsNull(V) then      { program knows what it does, but reproduces RTL behaviour }
  S := V
else
  S := NullAsStringValue;

bad code

NullStrictConvert := False;   { smelly, from now on Null variant loses its specifics }
S := V;

even worse code

try
  S := V;
except on Eaten: Exception do { stinky PHP-style, hiding error instead of fixing it }
  S := NullAsStringValue;
end;

NOTE: Most late Delphi.NET exhibits exactly the same behaviour on Null variants, so OP's remark about .NET is questionable.

Upvotes: 14

Uli Gerhardt
Uli Gerhardt

Reputation: 14001

Try setting NullStrictConvert to False.

As it's a global variable I use it like follows to minimize side effects:

var
  OldNullStrictConvert: Boolean;
begin
  OldNullStrictConvert := NullStrictConvert;
  NullStrictConvert := False;
  try
    // code containing conversions
  finally
    NullStrictConvert := OldNullStrictConvert;
  end;
end;

(In reality I have made a guardian interface out of this.)

NB: Where it's feasible I prefer code like Warren's.

Upvotes: 30

Related Questions