在 C++ Builder 12 中创建有效的 TValue<TNotifyEvent>

问题描述 投票:0回答:1
我需要在运行时使用 RTTI 分配事件属性。但我无法创建

TValue

 类型为
TNotifyEvent
始终是
void (__closure *)(class System::TObject *) __attribute__((fastcall))

我创建了辅助方法,可以在运行时协助设置事件,但不断收到 EInvalidCast 消息“无效的类类型转换”。

void __fastcall setProperty(TObject * component, const String name, TValue value) { auto * context = getContext(); // TRttiContext * auto * property = context->GetType(component->ClassType())->GetProperty(name); volatile String valueType = AnsiString(value.TypeInfo->Name); // "void (__closure *)(class System::TObject *) __attribute__((fastcall))" volatile String propertyType = property->PropertyType->Name; // "TNotifyEvent" volatile String oldType = AnsiString(property->GetValue(component).TypeInfo->Name); // "TNotifyEvent" property->SetValue(component, value); // Raising exception }
主叫方:
btn 是 TButton *

auto value = TValue::From<TNotifyEvent>(&closeBtnClick); setProperty(btn, "OnClick", value);
还尝试根据

这个问题使用TMethod,但引发了相同的异常: 上下文是 TRttiContext *

auto * method = context->GetType(__classid(TStandardPanel))->GetMethod("closeBtnClick"); TMethod * handler = new TMethod(); handler->Code = method->CodeAddress; handler->Data = this; auto value = TValue::From(TNotifyEvent(handler)); setProperty(btn, "OnClick", value);
但是当我直接分配它时它就起作用了:

btn->OnClick = &closeBtnClick;
如果从其他属性获取 TValue 并重新分配给当前属性,它也可以工作。

c++ c++builder rtti c++builder-12-athens
1个回答
0
投票

TNotifyEvent

 是 C++ 中的 
typedef
。它不是具有自己的 RTTI 的独特类型。  它只是一个别名,这就是为什么您会看到它的类型报告为 
void (__closure *)(class System::TObject *) __attribute__((fastcall))
,因为这是 C++ 所看到的实际类型。

这与 Delphi 不同,其中

TNotifyEvent

 是一种具有自己的 RTTI 的独特类型。

您的

TMethod

尝试是错误的。摆脱 
new
,您对 
TMethod*
 指针的类型转换是错误的。  你需要更多类似这样的东西:

TMethod handler; handler.Code = method->CodeAddress; handler.Data = this; auto value = TValue::From(reinterpret_cast<TNotifyEvent&>(handler));
或者:

auto value = TValue::From(*reinterpret_cast<TNotifyEvent*>(&handler));
或者:

TNotifyEvent handler; TMethod &m = reinterpret_cast<TMethod&>(handler); m.Code = method->CodeAddress; m.Data = this; auto value = TValue::From(handler);
但是,在任何这些情况下,您总是会得到 

TValue

 类型作为 
void (__closure *)(class System::TObject *) __attribute__((fastcall))
,因为这是 C++ 端 
TNotifyEvent
 的真实类型。

因此,要做您正在尝试的事情,您需要 Delphi RTTI

TNotifyEvent

。  您可以从
TRttiContext::FindType()
获取它,然后将其传递给
TValue::Make()
,例如:

PTypeInfo GetTNotifyEventTypeInfo() { auto * context = getContext(); auto * type = context->FindType(_D("System.Classes.TNotifyEvent")); return type->Handle; } ... auto handler = closeBtnClick; TValue value; TValue::Make(&handler, GetTNotifyEventTypeInfo(), value); setProperty(btn, _D("OnClick"), value);
但是,更通用(且正确)的解决方案是从您尝试分配的实际属性中查询 TypeInfo,例如:

PTypeInfo GetPropertyTypeInfo(TObject * component, const String name) { auto * context = getContext(); auto * type = context->GetType(component->ClassType()); auto * property = type->GetProperty(name); return property->PropertyType->Handle; } ... auto handler = closeBtnClick; TValue value; TValue::Make(&handler, GetPropertyTypeInfo(btn, _D("OnClick")), value); setProperty(btn, _D("OnClick"), value);
    
© www.soinside.com 2019 - 2024. All rights reserved.