No.
Во-первых, нет такого понятия, как "не-инстанцирован переменной." Вы создаете экземпляр его простым действием для ввода имени и типа в свой исходный файл.
Во-вторых, вы уже знаете все, что нужно знать о переменной, глядя на нее в исходном коде. Переменная перестает существовать после того, как ваша программа скомпилирована. После этого все это просто бит.
У указателя есть только тип во время компиляции. Во время выполнения все, что можно сделать с этим адресом, уже определено. Компилятор проверяет это, как вы уже отметили. Проверка типа переменной во время выполнения полезна только на языках, где тип переменной может меняться, как в динамических языках. Ближайший Delphi подходит к типу Variant
. Тип переменной всегда Variant
, но вы можете хранить в нем множество типов значений. Чтобы узнать, что он держит, вы можете использовать функцию VarType
.
В любое время, когда вы захотите использовать TypeInfo
, чтобы получить информацию о типе типа, связанного с переменной, вы также можете указать название, которое вас интересует; если переменная находится в области видимости, то вы можете найти ее объявление и использовать объявленный тип в своем вызове TypeInfo
.
Если вы хотите передать произвольный адрес функции и чтобы эта функция обнаружила информацию о типе для себя, вам не повезло. Вместо этого вам нужно будет передать значение PTypeInfo
в качестве дополнительного параметра. Это то, что делают все встроенные функции Delphi. Например, когда вы вызываете New
на переменную-указатель, компилятор добавляет дополнительный параметр, который содержит значение PTypeInfo
для типа, который вы выделяете. Когда вы вызываете SetLength
в динамическом массиве, компилятор вставляет значение PTypeInfo
для типа массива.
The answer that you gave предполагает, что вы ищете что-то иное, чем то, что вы просили.Учитывая ваш вопрос, я думал, что вы искали гипотетическую функцию, которая могла бы удовлетворить этот код:
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;
Давайте использовать IsClass
and IsObject
functions from the JCL построить эту функцию:
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;
Вы можете возразить, как я буду злоупотреблять эти функции, передавая то, что, очевидно, мусор в них. Но я думаю, что это только способ иметь смысл говорить об этой теме. Если вы знаете, что у вас никогда не будет значений мусора, вам не нужна функция, о которой вы просите, так как вы уже достаточно знаете о своей программе, чтобы использовать реальные типы для ваших переменных.
В целом, вы задаете неправильный вопрос. Вместо того, чтобы спрашивать, как вы определяете тип переменной или тип значения в памяти, , вы должны спросить, как вы попали в положение, когда вы еще не знаете типы переменных и свои данные.
У вас может быть «процедура Test (var AUntypedParam)» (или с «const» или «out» вместо «var»). –
Извините. Мой ответ должен был сказать «нетипированный параметр» вместо «нетипизированного указателя». Исправленный. –