2009-02-16 3 views
8

TypeInfo (Type) возвращает информацию о указанном типе, есть ли способ узнать типinfo для var?Как узнать, какой тип является var?

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

Этот код возвращает:

[Ошибка ДКК] Unit1.pas (354): E2133 TypeInfo стандартная функция ожидает, что идентификатор типа

Я знаю, что не экземпляр вар только указатель адрес. Во время компиляции компилятор анализирует и выполняет проверку безопасности типа.

Во время выполнения, есть ли способ узнать немного больше о var, только передавая его адрес?

ответ

2

Не то, чтобы я знал. Вы можете получить RTTI (информация о типе времени выполнения) в опубликованных свойствах класса, но не для «нормальных» переменных, таких как строки и целые числа и т. Д. Информации просто нет.

Кроме того, единственный способ передать var без передачи типа - использовать либо общий параметр TObject, общий тип (D2008, как и), либо как нетипизированный параметр. Я не могу придумать другой способ передать его, который бы даже скомпилировался.

+1

У вас может быть «процедура Test (var AUntypedParam)» (или с «const» или «out» вместо «var»). –

+0

Извините. Мой ответ должен был сказать «нетипированный параметр» вместо «нетипизированного указателя». Исправленный. –

28

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; 

Вы можете возразить, как я буду злоупотреблять эти функции, передавая то, что, очевидно, мусор в них. Но я думаю, что это только способ иметь смысл говорить об этой теме. Если вы знаете, что у вас никогда не будет значений мусора, вам не нужна функция, о которой вы просите, так как вы уже достаточно знаете о своей программе, чтобы использовать реальные типы для ваших переменных.

В целом, вы задаете неправильный вопрос. Вместо того, чтобы спрашивать, как вы определяете тип переменной или тип значения в памяти, , вы должны спросить, как вы попали в положение, когда вы еще не знаете типы переменных и свои данные.

+0

Ответ был уже хорошим, но ваше редактирование сделало его еще лучше. +1. – mghie

+0

Прошу прощения, моя челюсть упала на мгновение ... +1 – Wodzu

Смежные вопросы