いいえ。
まず、「インスタンス化されていない変数」のようなものはありません。名前を入力してソースファイルに入力するだけでインスタンス化できます。
次に、ソースコードで変数を確認することで、変数について知っておくべきことがすべてわかっています。プログラムがコンパイルされると、変数は存在しなくなります。その後、それはすべてほんの少しです。
ポインタはコンパイル時にのみ型を持ちます。実行時に、そのアドレスに対して実行できることはすべてすでに決定されています。すでに述べたように、コンパイラはそれをチェックします。実行時に変数の型をチェックすることは、動的言語のように、変数の型が変更される可能性のある言語でのみ役立ちます。それに最も近いDelphiは、そのVariant
タイプです。変数のタイプは常にVariant
ですが、多くのタイプの値を格納できます。それが何を保持しているかを知るために、VarType
関数を使用することができます。
TypeInfo
変数に関連付けられた型の型情報を取得するために使用したい場合はいつでも、関心のある型に直接名前を付けることができます。変数がスコープ内にある場合は、その宣言を見つけて、への呼び出しで宣言された型を使用できますTypeInfo
。
関数に任意のアドレスを渡し、その関数にそれ自体の型情報を検出させたい場合は、運が悪いです。PTypeInfo
代わりに、値を追加のパラメーターとして渡す必要があります。これが、すべての組み込みDelphi関数が行うことです。たとえばNew
、ポインタ変数を呼び出すと、コンパイラは、PTypeInfo
割り当てている型の値を保持する追加のパラメータを挿入します。動的配列を呼び出すとSetLength
、コンパイラーPTypeInfo
は配列型の値を挿入します。
あなたが与えた答えは、あなたが求めていたもの以外のものを探していることを示唆しています。あなたの質問を考えると、私はあなたがこのコードを満たすことができる架空の関数を探していると思いました:
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;
JCLのIsClass
andIsObject
関数を使用して、その関数を作成してみましょう。
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;
明らかにそれ以上では機能しませんS
がInstance
、どうなるか見てみましょうObj
:
Info := GetVariableTypeInfo(@Obj);
これにより、アクセス違反が発生するはずです。Obj
には値がないためIsClass
、IsObject
どちらも指定されていないメモリアドレスを読み取ります。おそらく、プロセスに属するアドレスではありません。変数のアドレスを入力として使用するルーチンを要求しましたが、単なるアドレスでは不十分です。
IsClass
それでは、IsObject
実際にどのように動作するかを詳しく見てみましょう。これらの関数は任意の値を取り、その値がオブジェクト(インスタンス)またはクラスのいずれかの特定の種類の値である可能性があるかどうかを確認します。次のように使用します。
// 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;
関数は変数について何も教えてくれず、保持している値についてだけ教えてくれることに注意してください。それでは、変数に関する型情報を取得する方法についての質問に答えるために、これらの関数についてはあまり考慮しません。
さらに、変数について知っているのはそのアドレスだけだとあなたは言いました。あなたが見つけた関数は変数のアドレスを取りません。それらは変数の値を取ります。これがデモンストレーションです:
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;
明らかにゴミであるものをそれらに渡すことによって、私がこれらの関数を悪用している方法に反対するかもしれません。しかし、それがこのトピックについて話すことが理にかなっている唯一の方法だと思います。ガベージ値がないことがわかっている場合は、変数に実際の型を使用するためのプログラムについてすでに十分に知っているので、とにかく要求している関数は必要ありません。
全体的に、あなたは間違った質問をしている。変数のタイプやメモリ内の値のタイプをどのように決定するかを尋ねる代わりに、変数とデータのタイプをまだ知らない位置に自分自身をどのように導いたかを尋ねる必要があります。