delphi - typage - tester le type d une variable c#



Comment savoir quel type est un var? (2)

Pas que je sache de. Vous pouvez obtenir RTTI (Run Time Type Information) sur les propriétés publiées d'une classe, mais pas pour les variables "normales" comme les chaînes et les entiers, etc. L'information n'est tout simplement pas là.

De plus, la seule façon de passer une var sans passer un type est d'utiliser soit un paramètre générique TObject, un type générique (D2008, comme dans), soit un paramètre non typé. Je ne peux pas penser à un autre moyen de le transmettre qui serait même compiler.

TypeInfo (Type) renvoie l'information sur le type spécifié, est-il possible de connaître le typeinfo d'un var?

var
  S: string;
  Instance: IObjectType;
  Obj: TDBGrid;
  Info: PTypeInfo;
begin
  Info:= TypeInfo(S);
  Info:= TypeInfo(Instance);
  Info:= TypeInfo(Obj);
end

Ce code renvoie:

[Erreur DCC] Unit1.pas (354): La fonction standard E2133 TYPEINFO attend un identificateur de type

Je sais qu'une var non instanciée est seulement une adresse de pointeur. Au moment de la compilation, le compilateur analyse et effectue le contrôle de sécurité de type.

Au moment de l'exécution, y a-t-il un moyen d'en savoir un peu plus sur un var, en passant seulement son adresse?


Non.

Premièrement, il n'existe pas de «variable non instanciée». Vous l'instanciez simplement en tapant son nom et son type dans votre fichier source.

Deuxièmement, vous savez déjà tout ce qu'il faut savoir sur une variable en la consultant dans votre code source. La variable cesse d'exister une fois que votre programme est compilé. Après cela, tout est juste un peu.

Un pointeur a seulement un type à la compilation. Au moment de l'exécution, tout ce qui peut être fait à cette adresse a déjà été déterminé. Le compilateur vérifie cela, comme vous l'avez déjà noté. La vérification du type d'une variable au moment de l'exécution n'est utile que dans les langues où le type d'une variable peut changer, comme dans les langages dynamiques. Le Delphi le plus proche vient à c'est avec son type Variant . Le type de la variable est toujours Variant , mais vous pouvez y stocker plusieurs types de valeurs. Pour savoir ce qu'il contient, vous pouvez utiliser la fonction VarType .

Chaque fois que vous pourriez vouloir utiliser TypeInfo pour obtenir les informations de type du type associé à une variable, vous pouvez également nommer directement le type qui vous intéresse; Si la variable est dans la portée, alors vous pouvez aller chercher sa déclaration et utiliser le type déclaré dans votre appel à TypeInfo .

Si vous voulez passer une adresse arbitraire à une fonction et que cette fonction découvre les informations de type, vous n'avez pas de chance. Vous devrez à la place passer la valeur PTypeInfo tant que paramètre supplémentaire. C'est ce que font toutes les fonctions Delphi intégrées. Par exemple, lorsque vous appelez New sur une variable pointeur, le compilateur insère un paramètre supplémentaire qui contient la valeur PTypeInfo pour le type que vous PTypeInfo . Lorsque vous appelez SetLength sur un tableau dynamique, le compilateur insère une valeur PTypeInfo pour le type de tableau.

La réponse que vous avez donnée suggère que vous cherchez autre chose que ce que vous avez demandé. Compte tenu de votre question, je pensais que vous étiez à la recherche d'une fonction hypothétique qui pourrait satisfaire ce code:

var
  S: string;
  Instance: IObjectType;
  Obj: TDBGrid;
  Info: PTypeInfo;
begin
  Info:= GetVariableTypeInfo(@S);
  Assert(Info = TypeInfo(string));

  Info:= GetVariableTypeInfo(@Instance);
  Assert(Info = TypeInfo(IObjectType));

  Info:= GetVariableTypeInfo(@Obj);
  Assert(Info = TypeInfo(TDBGrid));
end;

Utilisons les fonctions IsClass et IsObject du JCL pour construire cette fonction:

function GetVariableTypeInfo(pvar: Pointer): PTypeInfo;
begin
  if not Assigned(pvar) then
    Result := nil
  else if IsClass(PPointer(pvar)^) then
    Result := PClass(pvar).ClassInfo
  else if IsObject(PPointer(pvar)^) then
    Result := PObject(pvar).ClassInfo
  else
    raise EUnknownResult.Create;
end;

Il ne fonctionnera évidemment pas pour S ou Instance ci-dessus, mais voyons ce qui se passe avec Obj :

Info := GetVariableTypeInfo(@Obj);

Cela devrait donner une violation d'accès. Obj n'a aucune valeur, donc IsClass et IsObject IsClass tous deux une adresse mémoire non spécifiée, probablement pas celle qui appartient à votre processus. Vous avez demandé une routine qui utiliserait l'adresse d'une variable comme entrée, mais la simple adresse ne suffit pas.

Voyons maintenant de plus près comment IsClass et IsObject se comportent réellement. Ces fonctions prennent une valeur arbitraire et vérifient si la valeur semble être une valeur du type donné, soit un objet (instance) ou une classe. Utilisez-le comme ceci:

// This code will yield no assertion failures.
var
  p: Pointer;
  o: TObject;
  a: array of Integer;
begin
  p := TDBGrid;
  Assert(IsClass(p));

  p := TForm.Create(nil);
  Assert(IsObject(p));

  // So far, so good. Works just as expected.
  // Now things get interesting:

  Pointer(a) := p;
  Assert(IsObject(a));
  Pointer(a) := nil;
  // A dynamic array is an object? Hmm.

  o := nil;
  try
    IsObject(o);
    Assert(False);
  except
    on e: TObject do
      Assert(e is EAccessViolation);
  end;
  // The variable is clearly a TObject, but since it
  // doesn't hold a reference to an object, IsObject
  // can't check whether its class field looks like
  // a valid class reference.
end;

Notez que les fonctions ne vous disent rien sur les variables, seulement sur les valeurs qu'elles contiennent. Je ne considérerais donc pas vraiment ces fonctions pour répondre à la question de savoir comment obtenir des informations sur une variable.

De plus, vous avez dit que tout ce que vous savez de la variable est son adresse. Les fonctions que vous avez trouvées ne prennent pas l'adresse d'une variable. Ils prennent la valeur d'une variable. Voici une démonstration:

var
  c: TClass;
begin
  c := TDBGrid;
  Assert(IsClass(c));
  Assert(not IsClass(@c)); // Address of variable
  Assert(IsObject(@c)); // Address of variable is an object?
end;

Vous pourriez objecter à la façon dont j'abuse de ces fonctions en passant ce qui est évidemment des ordures en eux. Mais je pense que c'est le seul moyen de parler de ce sujet. Si vous savez que vous n'aurez jamais de valeurs inutiles, vous n'avez pas besoin de la fonction que vous demandez, car vous en savez déjà assez sur votre programme pour utiliser des types réels pour vos variables.

Dans l'ensemble, vous posez la mauvaise question. Au lieu de vous demander comment vous déterminez le type d'une variable ou le type d'une valeur en mémoire, vous devriez vous demander comment vous vous êtes mis dans la position où vous ne connaissez pas déjà les types de vos variables et vos données .





typeinfo