Easiest way to support backwards compatibility with a UPROPERTY

Here’s the problem I have.

My framework plugin needs to be able to support both Unreal Engine 4 and Unreal Engine 5. However, one of my classes has a map of names to particle resources. Unreal 5 needs Niagara particles, whereas Unreal 4 would need Cascade particle resources (because Niagara, last I checked, doesn’t exist in Unreal 4, at least not in a finished state). [This is also the reason I used raw pointers instead of TObjectPtr<>.]
The current code looks like this:

	/**
	 * Cascade particle resources for this skill.
	 *
	 * Cascade is a legacy feature and this only exists for such compatibility (and 4.27 compatibility).
	 * Please consider upgrading to Niagara for compatibility with future releases, as when Cascade is removed, this must also be removed.
	 */
	UPROPERTY(Category = "Skill|Cosmetic Settings (OPTIONAL)", EditDefaultsOnly)
	TMap<FName, UParticleSystem*> CascadeParticleResources;

	/**
	 * Niagara article resources for this skill.
	 */
	UPROPERTY(Category = "Skill|Cosmetic Settings (OPTIONAL)", EditDefaultsOnly)
	TMap<FName, UNiagaraSystem*> NiagaraParticleResources;

The alternative WOULD look like this:

	/**
	 * Particle resources for this skill.
	 */
	UPROPERTY(Category = "Skill|Cosmetic Settings (OPTIONAL)", EditDefaultsOnly)
#if ENGINE_MAJOR_VERSION 5
	TMap<FName, UNiagaraSystem*> NiagaraParticleResources;
#else
	TMap<FName, UParticleSystem*> CascadeParticleResources;
#endif

This is to allow developers to set up cosmetic resources for a skill, without having to do any programming to make those work, by using the framework’s Events system, or being able to display other resources (e.g. there’s a map for text resources for UI, such as skill descriptions, names, categories, etc.) on widgets.

However, obviously, this code wouldn’t compile. I can’t wrap UPROPERTYs in these either because that’s just how Unreal Header Tool is. And I also don’t want to have to copy-paste the ENTIRE framework just for Unreal 4 support, because if I did, updating it would be an absolute nightmare.

Any help would be appreciated. I really don’t know how I would do this.

I’ve thought of an idea that may solve this. Both Cascade and Niagara particles derive from UFXSystemAsset, so I will try that and post my results. It ought to work in both versions, hopefully, and I think they share many of the same functions. Worst-case scenario, is that I may have to cast between them (and that I know I can do with preprocessors) in the source code.

My recent findings: Switching the two properties to one TMap<FName, UFXSystemAsset*> works wonderfully. So in this exact instance we’re fine.

Still, I may not want to mark this as resolved, simply because of the general question of supporting backwards compatibility with UPROPERTY. Like, let’s say I wanted my classes to use TObjectPtr<> in UE5 and raw pointers in UE4 (ESPECIALLY if TObjectPtr<> is going to become a requirement in the future). That’s a perfect example of where this would be just all too useful.

I do wonder, though, perhaps I’d be able to use two headers for one class, one for UE4 and one for UE5, then just share the same source file and try to wrap those in preprocessors? I have no clue what else I would do. That, or maybe a custom macro would help. One to automatically swap the syntax based on the engine version I’m building against. I may try that out and see what happens, but for now, I’ll mark this as resolved, since I did technically find a solution.