Skip to content

Instantly share code, notes, and snippets.

@Steve-Himself
Last active July 24, 2017 04:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Steve-Himself/374e11c59d7b0ee68b919e12819177d6 to your computer and use it in GitHub Desktop.
Save Steve-Himself/374e11c59d7b0ee68b919e12819177d6 to your computer and use it in GitHub Desktop.
Autofac TupleRegistrationSource Spike
using System;
using System.Diagnostics;
namespace Autofac.Tuple
{
public interface IUnitOfWork
{
void Complete();
}
public class UnitOfWork : IUnitOfWork, IDisposable
{
public void Complete()
{
}
public void Dispose()
{
}
}
public interface IValueService
{
int GetNextValue();
}
public class ValueService : IValueService
{
public int GetNextValue()
{
return 0;
}
}
public interface IWidgetService
{
(string name, string description) GetWidget(int id);
}
public class WidgetService : IWidgetService
{
public (string name, string description) GetWidget(int id)
{
return default((string, string));
}
}
public interface IFooBarService
{
string Get();
}
public class FooBarService : IFooBarService
{
private (IWidgetService widgetService, Lazy<IValueService> valueService) _services;
private readonly IUnitOfWork _unitOfWork;
public FooBarService((IWidgetService, Lazy<IValueService>) services, IUnitOfWork u)
{
_services = services;
_unitOfWork = u;
}
public string Get()
{
Debug.Assert(_services.widgetService != null);
Debug.Assert(_services.valueService != null);
Debug.Assert(_unitOfWork != null);
return "FooBar";
}
}
}
using System;
namespace Autofac.Tuple
{
class Program
{
static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterSource(new ValueTupleRegistrationSource());
builder.RegisterSource(new TupleRegistrationSource());
builder.RegisterType<FooBarService>().As<IFooBarService>().InstancePerDependency();
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerDependency();
builder.RegisterType<ValueService>().As<IValueService>().InstancePerDependency();
builder.RegisterType<WidgetService>().As<IWidgetService>().InstancePerDependency();
var container = builder.Build();
var f = container.Resolve<IFooBarService>();
Console.WriteLine(f.Get());
Console.ReadKey();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Autofac.Builder;
using Autofac.Core;
namespace Autofac.Tuple
{
internal static class RegistrationOrderExtensions
{
internal const string RegistrationOrderMetadataKey = "__RegistrationOrder";
internal static long GetRegistrationOrder(this IComponentRegistration registration)
{
object value;
return registration.Metadata.TryGetValue(RegistrationOrderMetadataKey, out value) ? (long)value : long.MaxValue;
}
internal static IRegistrationBuilder<TLimit, TActivatorData, TSingleRegistrationStyle> InheritRegistrationOrderFrom<TLimit, TActivatorData, TSingleRegistrationStyle>(
this IRegistrationBuilder<TLimit, TActivatorData, TSingleRegistrationStyle> registration,
IComponentRegistration source)
where TSingleRegistrationStyle : SingleRegistrationStyle
{
var sourceRegistrationOrder = source.GetRegistrationOrder();
registration.RegistrationData.Metadata[RegistrationOrderMetadataKey] = sourceRegistrationOrder;
return registration;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Autofac.Builder;
using Autofac.Core;
namespace Autofac.Tuple
{
public class TupleRegistrationSource : TupleRegistrationSourceBase
{
private static readonly Type[] GenericTupleTypes =
{
typeof(Tuple<>),
typeof(Tuple<,>),
typeof(Tuple<,,>),
typeof(Tuple<,,,>),
typeof(Tuple<,,,,>),
typeof(Tuple<,,,,,>),
typeof(Tuple<,,,,,,>),
typeof(Tuple<,,,,,,,>)
};
protected override Type[] TupleTypes => GenericTupleTypes;
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Autofac.Builder;
using Autofac.Core;
namespace Autofac.Tuple
{
public abstract class TupleRegistrationSourceBase : IRegistrationSource
{
private static readonly MethodInfo CreateTupleRegistrationMethod =
typeof(TupleRegistrationSourceBase).GetTypeInfo().GetDeclaredMethod(nameof(CreateTupleRegistration));
public IEnumerable<IComponentRegistration> RegistrationsFor(Service service,
Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
{
if (registrationAccessor == null) throw new ArgumentNullException(nameof(registrationAccessor));
var swt = service as IServiceWithType;
if (swt == null || !swt.ServiceType.IsGenericType ||
TupleTypes.All(t => swt.ServiceType.GetGenericTypeDefinition() != t))
{
// It's not a request for the base handler type, so skip it.
return Enumerable.Empty<IComponentRegistration>();
}
var ownedInstanceType = swt.ServiceType.GetTypeInfo().GenericTypeArguments.First();
var ownedInstanceService = swt.ChangeType(ownedInstanceType);
var registrationCreator = CreateTupleRegistrationMethod.MakeGenericMethod(swt.ServiceType.GetTypeInfo());
var valueTypes = swt.ServiceType.GetTypeInfo().GenericTypeArguments;
return registrationAccessor(ownedInstanceService)
.Select(v => registrationCreator.Invoke(null, new object[] {service, v, swt, valueTypes}))
.Cast<IComponentRegistration>();
}
public bool IsAdapterForIndividualComponents => false;
public override string ToString()
{
return nameof(TupleRegistrationSource);
}
protected abstract Type[] TupleTypes { get; }
private static IComponentRegistration CreateTupleRegistration<T>(Service providedService, IComponentRegistration valueRegistration, IServiceWithType swt, Type[] types)
{
var rb = RegistrationBuilder.ForDelegate(
(c, p) =>
{
var tupleType = typeof(T);
var ctor = tupleType.GetConstructor(types);
var signature = new Lazy<string>(() => string.Join(", ", types.Select(t => t.Name).ToArray()));
var result = new List<object>();
foreach (var t in types)
{
var item = c.ComponentRegistry
.RegistrationsFor(swt.ChangeType(t))
.OrderBy(cr => cr.GetRegistrationOrder())
.Select(cr => c.ResolveComponent(cr, p))
.FirstOrDefault();
if (item == null)
{
throw new DependencyResolutionException(
$"Unable to resolve required component for {tupleType.Name} ({signature.Value})");
}
result.Add(item);
}
return (T)ctor.Invoke(result.ToArray());
})
.As(providedService)
.Targeting(valueRegistration)
.InheritRegistrationOrderFrom(valueRegistration);
return rb.CreateRegistration();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Autofac.Builder;
using Autofac.Core;
namespace Autofac.Tuple
{
public class ValueTupleRegistrationSource : TupleRegistrationSourceBase
{
private static readonly Type[] GenericTupleTypes =
{
typeof(ValueTuple<>),
typeof(ValueTuple<,>),
typeof(ValueTuple<,,>),
typeof(ValueTuple<,,,>),
typeof(ValueTuple<,,,,>),
typeof(ValueTuple<,,,,,>),
typeof(ValueTuple<,,,,,,>),
typeof(ValueTuple<,,,,,,,>)
};
protected override Type[] TupleTypes => GenericTupleTypes;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment