Skip to content

Instantly share code, notes, and snippets.

@SaxxonPike
Created February 15, 2018 23:34
Show Gist options
  • Save SaxxonPike/5e3984644721328347b9e286fa0760f3 to your computer and use it in GitHub Desktop.
Save SaxxonPike/5e3984644721328347b9e286fa0760f3 to your computer and use it in GitHub Desktop.
Autofac Module
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Autofac;
using Module = Autofac.Module;
namespace MyGist
{
public enum EventChannel
{
Draw,
Update
}
[AttributeUsage(AttributeTargets.Class)]
public class RegisteredAttribute : Attribute
{
public bool AutoDispose { get; set; } = true;
public bool IsSingleton { get; set; } = true;
}
[AttributeUsage(AttributeTargets.Event, AllowMultiple = true)]
public class EventSourceAttribute : Attribute
{
public EventSourceAttribute(EventChannel channel)
{
Channel = channel;
}
public EventChannel Channel { get; }
}
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class EventListenerAttribute : Attribute
{
public EventListenerAttribute(EventChannel channel)
{
Channel = channel;
}
public EventChannel Channel { get; }
}
public class MyModule : Module
{
private static IEnumerable<Type> GetTypes()
{
return typeof(TartModule)
.Assembly
.GetTypes();
}
protected override void Load(ContainerBuilder builder)
{
var types = GetTypes();
RegisterAllServices(builder, types);
base.Load(builder);
}
private void RegisterAllServices(ContainerBuilder builder, IEnumerable<Type> types)
{
var sources = new Dictionary<EventChannel, List<EventInfo>>();
var registeredTypes = types
.Where(t => t.GetCustomAttributes<RegisteredAttribute>().Any())
.ToArray();
foreach (var type in registeredTypes)
{
// Collect event sources.
foreach (var source in type.GetEvents(BindingFlags.Instance | BindingFlags.Public))
{
var sourceAttributes = source
.GetCustomAttributes<EventSourceAttribute>()
.ToArray();
if (!sourceAttributes.Any())
continue;
foreach (var attribute in sourceAttributes)
{
if (!sources.ContainsKey(attribute.Channel))
sources[attribute.Channel] = new List<EventInfo>();
sources[attribute.Channel].Add(source);
}
}
}
foreach (var type in registeredTypes)
{
// Register all servies marked as registered.
var registeredAttribute = type
.GetCustomAttributes<RegisteredAttribute>()
.Single();
var registrar = builder
.RegisterType(type)
.AsImplementedInterfaces()
.AsSelf()
.AutoActivate();
registrar = registeredAttribute.IsSingleton
? registrar.SingleInstance()
: registrar.InstancePerDependency();
registrar = registeredAttribute.AutoDispose
? registrar.OwnedByLifetimeScope()
: registrar.ExternallyOwned();
// Add activation handlers for listeners.
foreach (var listener in type.GetMethods(BindingFlags.Instance | BindingFlags.Public))
{
var listenerAttributes = listener
.GetCustomAttributes<EventListenerAttribute>()
.ToArray();
if (!listenerAttributes.Any())
continue;
registrar = listenerAttributes.Where(attribute => sources.ContainsKey(attribute.Channel))
.SelectMany(attribute => sources[attribute.Channel])
.Aggregate(registrar, (current, source) => current.OnActivating(activation =>
{
var sourceInstance = activation.Context.Resolve(source.DeclaringType);
var listenerInstance = activation.Instance;
source.AddEventHandler(sourceInstance, listener.CreateDelegate(source.EventHandlerType, listenerInstance));
}));
}
}
}
}
}
@SaxxonPike
Copy link
Author

Stick [Registered] on your concrete classes only, and get your container like so...

var builder = new Autofac.ContainerBuilder();
builder.RegisterModule<MyModule>();
var container = builder.Build();            

And events are automatically connected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment