2016-02-04 2 views
0

Я присваивающей как объекты и целые значения целочисленной переменной:Как проверить, если объект был присвоен целочисленной переменной

MyIntegerValue := Integer(MyObject); 
MyIntegerValue := 2; 
MyIntegerValue := 500; 
... 

Как проверить, если MyIntegerValue был назначен действительный объект?

+2

[TValue] (http://docwiki.embarcadero.com/Libraries/en/System.Rtti.TValue) может содержать как целые типы, так и экземпляры классов. Нет никакого безопасного способа сказать, что ваше целое указывает на экземпляр класса. –

+2

Самый простой способ сделать это: ** не делайте этого **, потому что это глупо. Не смешивайте целые числа и объекты, и у вас нет этой проблемы. Серьезно, когда вы начинаете задавать такие вопросы, это чрезвычайно убедительное доказательство того, что вы сделали что-то совершенно неправильное, и лучший способ выйти из этой ситуации - прекратить делать то, что вы делаете неправильно, что вы должен был задать этот вопрос. –

ответ

8

Как проверить, присвоен ли MyIntegerValue действительным объектом?

Вы не можете. Нет битов данных, указывающих, что удерживает Integer. Указатель (независимо от того, на что он указывает) - это всего лишь номер, относящийся к процессору. Это просто число, которое представляет собой адрес памяти.

Кроме того, ваша попытка сохранить указатель на объект в Integer не будет работать на 64-битных системах, вам нужно будет использовать NativeInt/NativeUInt вместо этого, в противном случае вы усечь значение указателя.

Чтобы сделать то, что вы просите, вам нужно будет использовать другую переменную, чтобы указать, что представляет значение Integer. Или лучше, используйте тип контейнера, который знает, что он держит, например TValue или Variant (и да, вы можете хранить указатели объектов в Variant с некоторой работой).

1

Вы не можете сделать это надежно, и вы не должны пытаться перехитрить безопасность типов в Delphi.


Для уточнения: С надежно я имею в виду следующие сценарии:

Вы присвоить целое переменной. Затем, позже вы вернетесь и хотите определить, является ли это целым числом или ссылкой на объект. У вас может возникнуть соблазн сначала проверить, является ли это ссылкой на объект, исследуя указанный блок памяти. Вы можете увидеть структуры и данные, показанные Free Consulting. Ага, ты думаешь, я сохранил ссылку на объект! Однако вы действительно хранили целое число, его значение просто совпадает с адресом объекта.

и

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

4

Вы должны следить за тем, что было сказано о типе безопасности и приведениях с very first comment к вам. Я не буду повторять этого и сосредоточиться на практическом подходе к конкретной проблеме. Это также ограничивает обсуждение 32-битной целью (поскольку вы задаете вопрос SizeOf(Integer) = SizeOf(Pointer));

Прежде всего, поскольку объекты являются указателями (как вы узнали из других ответов), его свойства, наложенные платформой, могли бы отличить действительный указатель (действительный!) И целочисленное значение.Посмотрите, как Windows, сказать указатель символов и перечисленные значения друг от друга:

function Is_IntResource(lpszType: PChar): BOOL; 
begin 
    Result := ULONG_PTR(lpszType) shr 16 = 0; 
end; 

Это использует тот факт, что нет данных пользовательского режима не могут быть выделены в этой малой области памяти на 32-битной платформе Windows, и, таким образом, , нет действительного значения указателя p < 65536 может существовать.

Далее вы можете использовать Delphi-специфический внутренний формат данных экземпляров объекта, чтобы проверить, если указатель действительно экземпляр объекта:

/// <summary> 
/// Verifies that the argument points to valid object instance. 
/// </summary> 
/// <exception cref="EAccessViolation"> 
/// If segmentation fault occurs while attempting to read VMT and/or its 
/// field from the specified memory address. 
/// </exception> 
/// <remarks> 
/// Delphi only, incompatible with FPC. 
/// </remarks> 
/// <example> 
/// <code lang="Delphi"> 
///  procedure TForm1.FormCreate(Sender: TObject); 
///  begin 
///  ShowMessage(BoolToStr(IsInstance(Self), True)); 
///  end; 
/// </code> 
/// </example> 
function IsInstance(Data: Pointer): Boolean; 
var 
    VMT: Pointer; 
begin 
    VMT := PPointer(Data)^; 
    Result := PPointer(PByte(VMT) + vmtSelfPtr)^ = VMT; 
end; 

Эта функция анализирует V irtual M еню T способный для подписи Delphi RTL и (заданные операции чтения памяти были успешными и проверка сигнатуры прошла) идентифицирует произвольный указатель как экземпляр TObject (или потомок).

nil/0: Вы должны взять даже более специальные меры предосторожности, о 0 значений указателя, так как это довольно значимое, как Pointer, а также часто, как Integer.

+0

Кроме того, 32-разрядная Windows IIRC также имеет зарезервированную область памяти в верхней части адресного пространства, что означает, что небольшие отрицательные значения также могут быть распознаны. –

+0

+1 [Внутренние форматы данных (Delphi) - Типы классов] (http://docwiki.embarcadero.com/RADStudio/Seattle/en/Internal_Data_Formats#Class_Types) для ссылки VMT - см. Константу 'vmtSelfPtr' – fantaghirocco

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