Dynamic Classes
The Core/DynamicClass package allows for creating new types at runtime. The reflection information for this dynamic types is 100% compatible with the static reflection information implemented in the Core. This means that code that is supposed to work with reflection information (like for example a GUI component to edit properties) will work with DynamicClasses.
Creating a Dynamic Class
To create a dynamic class, first you have to register the properties that you are going to need. In this example I am going to use the following types: NsByte, NsUInt16, Ptr<Resource> and NsFloat32.
Ptr<BaseComponent> byteProperty = DynamicClass::RegisterType<NsByte>();
Ptr<BaseComponent> wordProperty = DynamicClass::RegisterType<NsUInt16>();
Ptr<BaseComponent> resourceProperty = DynamicClass::RegisterType<Ptr<Resource> >();
Ptr<BaseComponent> floatProperty = DynamicClass::RegisterType<NsFloat32>();
Now, that we have registered the types properties are added to a new dynamic class
// struct DynamicClass
//{
// NsByte byte0;
// NsUInt16 word;
// Ptr<Resource> resource;
// NsByte byte1;
// NsFloat32 float[4];
//};
Ptr<DynamicClass> dynClass = NsCreateComponent<DynamicClass>(NSS(DynClass));
dynClass->AddProperty(NSS(byte0), byteProperty);
dynClass->AddProperty(NSS(word), wordProperty);
dynClass->AddProperty(NSS(resource), resourceProperty);
dynClass->AddProperty(NSS(byte1), byteProperty);
dynClass->AddPropertyArray(NSS(floats), floatProperty, 4);
Setting Default Values
Before creating instances from the dynamic class, we must set the default values for each property.
dynClass->Set<NsByte>(NSS(byte0), 32);
dynClass->Set<NsUInt16>(NSS(word), 44);
Ptr<Resource> resource = NsCreateComponent<Resource>(500.0f, 600.0f);
dynClass->Set<Ptr<Resource> >(NSS(resource), resource);
dynClass->Set<NsByte>(NSS(byte1), 192);
dynClass->Set<NsFloat32>(NSS(floats), 0, 0.0f);
dynClass->Set<NsFloat32>(NSS(floats), 1, 1.0f);
dynClass->Set<NsFloat32>(NSS(floats), 2, 2.0f);
dynClass->Set<NsFloat32>(NSS(floats), 3, 3.0f);
Creating instances
Once the dynamic class is properly configured, you can create an instance and Set/Get properties.
Ptr<DynamicClassInstance> instance = dynClass->CreateInstance();
/// Set properties
instance->Set<NsByte>(NSS(byte0), 240);
instance->Set<NsUInt16>(NSS(word), 1045);
Ptr<Resource> resource = NsCreateComponent<Resource>(1500.0f, 1600.0f);
instance->Set<Ptr<Resource> >(NSS(resource), resource);
instance->Set<NsByte>(NSS(byte1), 12);
instance->Set<NsFloat32>(NSS(floats), 0, 10.0f);
instance->Set<NsFloat32>(NSS(floats), 1, 11.0f);
instance->Set<NsFloat32>(NSS(floats), 2, 12.0f);
instance->Set<NsFloat32>(NSS(floats), 3, 13.0f);
/// Get properties
NsByte byte0 = instance->Get<NsByte>(NSS(byte0));
NsUInt16 word = instance->Get<NsUInt16>(NSS(word));
Ptr<Resource> resource = instance->Get<Ptr<Resource>>(NSS(resource));
NsByte byte1 = instance->Get<NsByte>(NSS(byte1));
NsFloat32 float0 = instance->Get<NsFloat32>(NSS(floats), 0);
NsFloat32 float1 = instance->Get<NsFloat32>(NSS(floats), 1);
NsFloat32 float2 = instance->Get<NsFloat32>(NSS(floats), 2);
NsFloat32 float3 = instance->Get<NsFloat32>(NSS(floats), 3);
Serializing / Unserializing
Both dynamic classes and instances can be serialized as a normal type.
{
// class serialization
Ptr<ISerializationManager> sm = NsCreateComponent(NSS(SerializationManager));
Ptr<IStream> stream = NsCreateComponent(NSS(MemoryStream));
{
sm->SerializeBegin(stream);
sm->Serialize(dynClass);
sm->SerializeEnd();
}
// instance serialization
Ptr<ISerializationManager> sm = NsCreateComponent(NSS(SerializationManager));
Ptr<IStream> stream = NsCreateComponent(NSS(MemoryStream));
{
sm->SerializeBegin(stream);
sm->Serialize(instance);
sm->SerializeEnd();
}
}
Reflection information
As said above, Dynamic Classes store reflection information that is compatible with the the static reflection supported by Noesis.
const TypeClass* type = instance->GetType();
NS_UNITTEST_CHECK(type ->GetNumProperties() == 5);
const TypeProperty* typeProperty = typeClass->GetProperty(0);
NS_UNITTEST_CHECK(typeProperty->GetContentType() == TypeOf<NsByte>::Get());