2009-02-16 15 views
8

TypeInfo (Type) devuelve la información sobre el tipo especificado, ¿hay alguna forma de conocer el typeinfo de una var?¿Cómo saber qué tipo es una var?

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

Este código devuelve:

[Error DCC] Unit1.pas (354): E2133 TYPEINFO función estándar espera un identificador de tipo de

sé un var no instanciada es solamente un puntero dirección. En tiempo de compilación, el compilador analiza y hace el tipo de verificación de seguridad.

En tiempo de ejecución, ¿hay alguna manera de saber un poco más acerca de una var, solo transfiriendo su dirección?

Respuesta

2

No es que yo sepa. Puede obtener RTTI (información de tipo de tiempo de ejecución) sobre las propiedades publicadas de una clase, pero no para variables "normales" como cadenas y enteros, etc. La información simplemente no está allí.

Además, la única forma de pasar una var sin pasar un tipo es usar un parámetro TObject genérico, un tipo genérico (D2008, como en) o un parámetro sin tipo. No puedo pensar en otra forma de pasarlo que incluso compilara.

+1

Puede tener "procedure Test (var AUntypedParam)" (o con "const" o "out" en lugar de "var"). –

+0

Lo siento. Mi respuesta debería haber dicho "parámetro sin tipo" en lugar de "puntero sin tipo". Corregido –

28

En primer lugar, no hay tal cosa como una "variable no instanciada." Lo instancia por el mero hecho de escribir su nombre y escribirlo en su archivo fuente.

En segundo lugar, ya sabes todo lo que hay que saber sobre una variable mirándola en tu código fuente. La variable deja de existir una vez que se compila su programa. Después de eso, todo es solo bits.

Un puntero solo tiene un tipo en tiempo de compilación. En tiempo de ejecución, todo lo que se puede hacer a esa dirección ya ha sido determinado. El compilador verifica eso, como ya anotó. Comprobar el tipo de variable en tiempo de ejecución solo es útil en los idiomas en los que el tipo de variable podría cambiar, como en los lenguajes dinámicos. Lo más cercano a Delphi es con su tipo Variant. El tipo de variable siempre es Variant, pero puede almacenar muchos tipos de valores en él. Para saber qué contiene, puede usar la función VarType.

Cualquier momento que desee utilizar TypeInfo para obtener la información de tipo del tipo asociado a una variable, también puede nombrar directamente el tipo que le interese; si la variable está dentro del alcance, puede buscar su declaración y usar el tipo declarado en su llamada al TypeInfo.

Si desea pasar una dirección arbitraria a una función y hacer que esa función descubra la información del tipo por sí misma, no tiene suerte. En su lugar, deberá pasar el valor PTypeInfo como un parámetro adicional. Eso es lo que hacen todas las funciones Delphi integradas. Por ejemplo, cuando llama al New en una variable de puntero, el compilador inserta un parámetro adicional que contiene el valor PTypeInfo para el tipo que está asignando. Cuando llama al SetLength en una matriz dinámica, el compilador inserta un valor PTypeInfo para el tipo de matriz.

The answer that you gave sugiere que usted está buscando algo diferente a lo que usted solicitó.Dada su pregunta, pensé que estabas buscando una hipotética función que podría satisfacer este código:

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; 

Usemos el IsClass and IsObject functions from the JCL para construir esa función:

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; 

Es obvio que no va a funcionar para S o Instance arriba, pero vamos a ver qué pasa con Obj:

Info := GetVariableTypeInfo(@Obj); 

Eso debería dar un acceso violación. Obj no tiene ningún valor, por lo que IsClass y IsObject leerán una dirección de memoria no especificada, probablemente no una que pertenezca a su proceso. Usted solicitó una rutina que usaría la dirección de una variable como entrada, pero la mera dirección no es suficiente.

Ahora echemos un vistazo más de cerca cómo se comportan realmente IsClass y IsObject. Esas funciones toman un valor arbitrario y comprueban si el valor se parece a, podría ser un valor del tipo dado, ya sea objeto (instancia) o clase. Utilizar de esta manera:

// 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; 

en cuenta que las funciones le dicen nada sobre las variables, sólo alrededor de los valores que poseen. Realmente no consideraría esas funciones, entonces, para responder la pregunta de cómo obtener información sobre una variable.

Además, ha dicho que todo lo que sabe sobre la variable es su dirección. Las funciones que encontraste no toman la dirección de una variable. Toman el valor de una variable. He aquí una demostración:

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; 

Es posible oponerse a la forma en que estoy abusando de estas funciones haciendo pasar lo que es, obviamente, la basura en ellos. Pero creo que esa es la forma solo tiene sentido hablar sobre este tema. Si sabes que nunca tendrás valores basura, entonces no necesitas la función que estás pidiendo de todos modos porque ya sabes lo suficiente sobre tu programa para usar tipos reales para tus variables.

En general, usted está haciendo la pregunta incorrecta. En lugar de preguntar cómo determina el tipo de una variable o el tipo de un valor en la memoria, debe preguntar cómo se metió en la posición en la que aún no conoce los tipos de sus variables y sus datos.

+0

La respuesta ya era buena, pero su edición lo hizo aún mejor. +1. – mghie

+0

Lo siento, mi mandíbula cayó por un momento ... +1 – Wodzu

Cuestiones relacionadas