Created
November 13, 2023 22:05
-
-
Save PizzaConsole/47b8f4e289cd87e9e61316eab7c68490 to your computer and use it in GitHub Desktop.
Dependency Injection in Godot
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class ConstrainedRequestPostProcessor<TRequest, TResponse> | |
: IRequestPostProcessor<TRequest, TResponse> | |
where TRequest : class | |
{ | |
public ConstrainedRequestPostProcessor() | |
{ | |
} | |
public Task Process(TRequest request, TResponse response, CancellationToken cancellationToken) | |
{ | |
return Task.CompletedTask; | |
} | |
} | |
public class DependencyInjectionSystem : Node | |
{ | |
private static DependencyInjectionSystem _instance; | |
public static DependencyInjectionSystem Instance | |
{ | |
get | |
{ | |
if (_instance == null) | |
{ | |
_instance = new DependencyInjectionSystem(); | |
} | |
return _instance; | |
} | |
} | |
private SimpleInjector.Container container; | |
public override void _EnterTree() | |
{ | |
base._EnterTree(); | |
container = new SimpleInjector.Container(); | |
var type = typeof(IGlobal); // Get the type of our interface | |
// Get the assemblies associated with our project | |
var types = AppDomain.CurrentDomain.GetAssemblies() | |
.SelectMany(s => s.GetTypes()) // Get all the types | |
.Where(p => type.IsAssignableFrom(p) && !p.IsInterface); // Filter to find any type that can be assigned to an IModule | |
foreach (var typ in types) | |
{ | |
var serviceType = Type.GetType(typ.AssemblyQualifiedName.Replace(typ.Name, $"I{typ.Name}")); | |
container.RegisterSingleton(typ, typ); | |
} | |
// do registrations here | |
container.RegisterMediator(); | |
//container.Register<InputController>(SimpleInjector.Lifestyle.Singleton); | |
container.Verify(); | |
} | |
internal object Resolve(Type fieldType) | |
{ | |
return container.GetInstance(fieldType); | |
} | |
} | |
public class GenericPipelineBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> | |
{ | |
public GenericPipelineBehavior() | |
{ | |
} | |
public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next) | |
{ | |
var response = await next(); | |
return response; | |
} | |
} | |
public class GenericRequestPostProcessor<TRequest, TResponse> : IRequestPostProcessor<TRequest, TResponse> | |
{ | |
public GenericRequestPostProcessor() | |
{ | |
} | |
public Task Process(TRequest request, TResponse response, CancellationToken cancellationToken) | |
{ | |
return Task.CompletedTask; | |
} | |
} | |
public class GenericRequestPreProcessor<TRequest> : IRequestPreProcessor<TRequest> | |
{ | |
public GenericRequestPreProcessor() | |
{ | |
} | |
public Task Process(TRequest request, CancellationToken cancellationToken) | |
{ | |
return Task.CompletedTask; | |
} | |
} | |
public class InjectAttribute : Attribute | |
{ | |
} | |
public static class InjectorExtensions | |
{ | |
public static void ResolveDependencies(this object node) | |
{ | |
var dis = DependencyInjectionSystem.Instance; | |
var at = typeof(InjectAttribute); | |
var fields = node.GetType() | |
.GetRuntimeFields() | |
.Where(f => f.GetCustomAttributes(at, true).Any()); | |
foreach (var field in fields) | |
{ | |
var obj = dis.Resolve(field.FieldType); | |
try | |
{ | |
field.SetValue(node, obj); | |
} | |
catch (InvalidCastException) | |
{ | |
GD.PrintErr($"Error converting value " + | |
$"{obj} ({obj.GetType()})" + | |
$" to {field.FieldType}"); | |
throw; | |
} | |
} | |
} | |
public static void RegisterMediator(this SimpleInjector.Container container) | |
{ | |
var assemblies = GetAssemblies().ToArray(); | |
container.RegisterSingleton<IMediator, Mediator>(); | |
container.Register(typeof(IRequestHandler<,>), assemblies); | |
RegisterHandlers(container, typeof(INotificationHandler<>), assemblies); | |
RegisterHandlers(container, typeof(IRequestExceptionAction<,>), assemblies); | |
RegisterHandlers(container, typeof(IRequestExceptionHandler<,,>), assemblies); | |
//Pipeline | |
container.Collection.Register(typeof(IPipelineBehavior<,>), new[] | |
{ | |
typeof(RequestExceptionProcessorBehavior<,>), | |
typeof(RequestExceptionActionProcessorBehavior<,>), | |
typeof(RequestPreProcessorBehavior<,>), | |
typeof(RequestPostProcessorBehavior<,>), | |
typeof(GenericPipelineBehavior<,>) | |
}); | |
container.Collection.Register(typeof(IRequestPreProcessor<>), new[] { typeof(GenericRequestPreProcessor<>) }); | |
container.Collection.Register(typeof(IRequestPostProcessor<,>), new[] { typeof(GenericRequestPostProcessor<,>), typeof(ConstrainedRequestPostProcessor<,>) }); | |
container.Register(() => new ServiceFactory(container.GetInstance), Lifestyle.Singleton); | |
} | |
private static void RegisterHandlers(SimpleInjector.Container container, Type collectionType, Assembly[] assemblies) | |
{ | |
// we have to do this because by default, generic type definitions (such as the | |
// Constrained Notification Handler) won't be registered | |
var handlerTypes = container.GetTypesToRegister(collectionType, assemblies, new TypesToRegisterOptions | |
{ | |
IncludeGenericTypeDefinitions = true, | |
IncludeComposites = false, | |
}); | |
container.Collection.Register(collectionType, handlerTypes); | |
} | |
private static IEnumerable<Assembly> GetAssemblies() | |
{ | |
yield return typeof(IMediator).GetTypeInfo().Assembly; | |
yield return typeof(DependencyInjectionSystem).GetTypeInfo().Assembly; | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class DependencyInjectionSystem : Node | |
{ | |
private static DependencyInjectionSystem _instance; | |
public static DependencyInjectionSystem Instance | |
{ | |
get | |
{ | |
if (_instance == null) | |
{ | |
_instance = new DependencyInjectionSystem(); | |
} | |
return _instance; | |
} | |
} | |
private SimpleInjector.Container container; | |
public override void _EnterTree() | |
{ | |
base._EnterTree(); | |
container = new SimpleInjector.Container(); | |
var type = typeof(IGlobal); // Get the type of our interface | |
// Get the assemblies associated with our project | |
var types = AppDomain.CurrentDomain.GetAssemblies() | |
.SelectMany(s => s.GetTypes()) // Get all the types | |
.Where(p => type.IsAssignableFrom(p) && !p.IsInterface); // Filter to find any type that can be assigned to an IModule | |
foreach (var typ in types) | |
{ | |
var serviceType = Type.GetType(typ.AssemblyQualifiedName.Replace(typ.Name, $"I{typ.Name}")); | |
container.RegisterSingleton(typ, typ); | |
} | |
// do registrations here | |
container.RegisterMediator(); | |
//container.Register<InputController>(SimpleInjector.Lifestyle.Singleton); | |
container.Verify(); | |
} | |
internal object Resolve(Type fieldType) | |
{ | |
return container.GetInstance(fieldType); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class GameMenu : Control | |
{ | |
[Inject] | |
protected GameManager _gameManager; | |
[Signal] | |
public delegate void ResetRoom(); | |
// Called when the node enters the scene tree for the first time. | |
public override void _Ready() | |
{ | |
this.ResolveDependencies(); | |
//Connect(nameof(ResetRoom), _gameManager, nameof(GameManager.ResetRoom)); | |
} | |
public void OnResetPressed() | |
{ | |
EmitSignal(nameof(ResetRoom)); | |
} | |
//LISTEN for when, Player shouts its controller name and function | |
private void OpenGameMenu() | |
{ | |
//Menu.Show() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment