Where do i declare my IOC Container?

I am trying to figure out a good place to declare my inversion of control container.

I have placed it inside the main project header file:

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "Engine.h"
#include "Runtime/Core/Public/Misc/TypeContainer.h"

TTypeContainer<> IOCContainer;

And inside my ATESTGameModeBase I am registering my classes:

ATESTGameModeBase::ATESTGameModeBase() {
	IOCContainer.RegisterClass<IDebugHelper, UOnScreenDebugHelper>();
}

And where i need to use it, I am calling it like so:

auto debugHelper = IOCContainer.GetInstance<IDebugHelper>();

When i compile, i get the error:

Severity Code Description Project File Line Suppression
State Error LNK2005 “class
TTypeContainer<0> IOCContainer”
(?IOCContainer@@3V?$TTypeContainer@$0A@@@A)
already defined in
PCH.TEST.h.obj TEST G:\Programming\TEST\Intermediate\ProjectFiles\Module.TEST.cpp.obj 1

Where is a good place to place my IOC container? It obviously needs to be accessed from anywhere, but it looks like this common file is problematic? What’s common practice? I can find literally no examples, anywhere… at all. Search google for TTypeContainer, only the source engine test comes up.

I have been following: Engine/Source/Runtime/Core/Private/Tests/Misc/TypeContainerTest.cpp but this example does not provide much in terms of real life example.


For completeness, here is my interface:

#pragma once

// UE includes
#include "Runtime/Core/Public/Misc/TypeContainer.h"

// 
#include "IDebugHelper.generated.h"

/**
 *
 */
UINTERFACE()
class TEST_API UDebugHelper : public UInterface
{
	GENERATED_BODY()
};


class IDebugHelper
{
	GENERATED_BODY()
public:
	virtual void WriteInfo() = 0;
};

// Expose_TNameOf(IDebugHelper) // If i add, there is an error: ')': Bad command or expression?
// I found out that this must be in the .cpp file

and here is my implementation:

#pragma once

// UE includes

// Project includes
#include "Abstracts/IDebugHelper.h"

// 
#include "OnScreenDebugHelper.generated.h"

/**
 *
 */
UCLASS()
class UOnScreenDebugHelper : public UObject, public IDebugHelper
{
	GENERATED_BODY()
public:
	void WriteInfo() override;
};

Figured it out. -

Start with an interface:

IDebugHelper.h

#pragma once
struct IDebugHelper
{
public:
	virtual void WriteInfo() = 0;
};

DebugHelper.cpp

#include "TEST.h"
#include "IDebugHelper.h"
#include "Runtime/Core/Public/Templates/UnrealTypeTraits.h"

Expose_TNameOf(IDebugHelper)

Now for the implementation:

OnScreenDebugHelper.h

#pragma once

// Project includes
#include "Abstracts/IDebugHelper.h"

class OnScreenDebugHelper : public IDebugHelper
{
public:
	void WriteInfo() override;
};

OnScreenDebugHelper.cpp

#include "TEST.h"
#include "OnScreenDebugHelper.h"

void OnScreenDebugHelper::WriteInfo()
{    
}

Now to register your interface to your implementation on an ioc container

TESTGameInstanceBase.h

#pragma once

// UE includes
#include "Engine/GameInstance.h"
#include "Runtime/Core/Public/Misc/TypeContainer.h"

#include "TESTGameInstanceBase.generated.h"

class TEST_API UTESTGameInstanceBase : public UGameInstance
{
	GENERATED_BODY()    
public:    	
	UTESTGameInstanceBase();    
	TTypeContainer<>& GetIOCContainer() { return this->iOCContainer; }    
private:    
	TTypeContainer<> iOCContainer;    
};

TESTGameInstanceBase.cpp

#include "TEST.h"
#include "Models/GameInstances/TESTGameInstanceBase.h"

// 
#include "Abstracts/IDebugHelper.h"
#include "Helpers/OnScreenDebugHelper.h"

UTESTGameInstanceBase::UTESTGameInstanceBase() {
	this->iOCContainer.RegisterClass<IDebugHelper, UOnScreenDebugHelper>(ETypeContainerScope::Instance);
}

And finally, to use it:

if (GetWorld() != nullptr)
{
	if (this->GetGameInstance() != nullptr)
	{
		TSharedPtr<IDebugHelper> debugHelper = ((UMainGameInstance*)this->GetGameInstance())->GetIOCContainer().GetInstance<IDebugHelper>();
	}
}

For people still coming across this - I have prepared a github example of IOC in Unreal Engine - https://github.com/jimmyt1988/UE-Testing

1 Like