Last active
July 24, 2017 04:31
-
-
Save Steve-Himself/374e11c59d7b0ee68b919e12819177d6 to your computer and use it in GitHub Desktop.
Autofac TupleRegistrationSource Spike
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
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"; | |
} | |
} | |
} |
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
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(); | |
} | |
} | |
} |
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
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; | |
} | |
} | |
} |
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
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; | |
} | |
} |
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
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(); | |
} | |
} | |
} |
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
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