If that is the requirement, then it’s probably better to define the file format in terms of binary structures, and have a method on your objects to “inhale this structure” and “exhale this structure,” which lets you fully de-couple properties from the file format. You do need to write those two functions, but they are then the clear interface, and give you full freedom for the file and network serialization.
Trying to look up properties one by one is unlikely to work well if you actually have a goal of high performance – whether you do it by map, name, or number, doesn’t matter; the fact that you do any kind of lookup per property is the high-order bit here.
Personally, when I do these inhale/exhale things, I end up writing a simple visitor template, something like:
template<typename T> void UMyObject::visit(T st) {
visit(st.someInt, MyIntProp);
visit(st.someString, MyStringProp);
visit(st.someFloat, MyFloatProp);
visit(st.someOtherFloat, MyOtherFloatProp);
}
void UMyObject::Inhale(FileStruct const &src) {
visit(src);
AfterPropsChanged();
}
void UMyObject::Exhale(FileStruct &dst) {
BeforePropsSave();
visit(dst);
}
And then define appropriate visit() function specializations for updating whatever your member types and widgets are – they’re typically reusable.
You will then have one step that is the “file format handler” that knows how to read/write your file format, using the defined structs, and then use those structs as the interface to your Unreal actors. This de-couples the I/O and lets you be as efficient as you need.
Also, that “file format structs” library could conceivably be used outside of Unreal, too, should that ever be needed.