Commits

Anonymous committed 4062837

Misc cleanup and accumulatd changes.

  • Participants
  • Parent commits ecc601a
  • Branches 2.0-experimental

Comments (0)

Files changed (11)

File Autofac.Tests/Autofac.Tests.csproj

     <Compile Include="OwnedInstancesTests.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="ReflectiveRegistrationTests.cs" />
+    <Compile Include="LifetimeEntryPointsTests.cs" />
     <Compile Include="TypedParameterTests.cs" />
   </ItemGroup>
   <ItemGroup>

File Autofac.Tests/ContainerTests.cs

             var lifetime = container.BeginLifetimeScope();
             var hello = lifetime.Resolve<string>();
 
-            // The context in Activated should be the root one, as hello
-            // is a singleton - not the nested one.
+            // The context in Activated should be the nested one, as
+            // hello is per-lifetime-scope.
             Assert.AreSame(lifetime.Resolve<object>(), fromContext);
         }
 
             var lifetime = container.BeginLifetimeScope();
             var hello = lifetime.Resolve<string>();
 
-            // The context in Activated should be the root one, as hello
-            // is a singleton - not the nested one.
+            // The context in Activated should be the nested one.
             Assert.AreSame(lifetime.Resolve<object>(), fromContext);
         }
 

File Autofac.Tests/GeneratedFactoriesTests.cs

             Assert.AreEqual("aaa", str);
         }
 
+        delegate string CharCountStringFactory(char c, int count);
+
+        [Test]
+        public void CanAutoGenerateFactoriesFromCustomDelegateTypes()
+        {
+            var container = new Container();
+            container.ComponentRegistry.AddDynamicRegistrationSource(new AutoGeneratedFactoryRegistrationSource());
+            container.RegisterType<string>();
+
+            var sf = container.Resolve<CharCountStringFactory>();
+            var str = sf('a', 3);
+
+            Assert.AreEqual("aaa", str);
+        }
+
         [Test]
         public void WillNotAutoGenerateFactoriesWhenProductNotRegistered()
         {

File Autofac.Tests/LifetimeEntryPointsTests.cs

+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using NUnit.Framework;
+
+namespace Autofac.Tests
+{
+    [TestFixture]
+    public class LifetimeEntryPointsTests
+    {
+        public delegate int AddOperation(int a, int b);
+
+        public class Counter
+        {
+            public int Count;
+        }
+
+        public class Adder : IDisposable
+        {
+            Counter _counter;
+
+            public Adder(Counter counter)
+            {
+                _counter = counter;
+            }
+
+            public int Add(int a, int b)
+            {
+                return a + b;
+            }
+
+            public void Dispose()
+            {
+                _counter.Count++;
+            }
+        }
+
+        [Test]
+        public void ExecutesOperationInNestedScope()
+        {
+            var container = new Container();
+            container.RegisterType<Counter>().SingleInstance();
+            container.RegisterType<Adder>().UnsharedInstances();
+
+            //container.RegisterDelegate<AddOperation>(c =>
+            //{
+            //    var l = c.Resolve<ILifetimeScope>();
+            //    return (a, b) =>
+            //    {
+            //        using (var inner = l.BeginLifetimeScope())
+            //            return inner.Resolve<Adder>().Add(a, b);
+            //    };
+            //});
+
+            container.RegisterLifetimeEntryPoint<AddOperation>((c, p) =>
+                c.Resolve<Adder>().Add(p.Positional<int>(0), p.Positional<int>(1)));
+
+            var op = container.Resolve<AddOperation>();
+
+            var counter = container.Resolve<Counter>();
+            Assert.AreEqual(0, counter.Count);
+
+            var ret = op(1, 2);
+
+            Assert.AreEqual(3, ret);
+
+            Assert.AreEqual(1, counter.Count);
+        }
+
+        [Test]
+        public void AppliesNameToNestedScope()
+        {
+            var container = new Container();
+            container.RegisterType<Counter>().SingleInstance();
+            container.RegisterType<Adder>().InstancePer("add-op");
+            container.RegisterLifetimeEntryPoint<AddOperation>("add-op", (c, p) =>
+                c.Resolve<Adder>().Add(p.Positional<int>(0), p.Positional<int>(1)));
+
+            // Will throw if scope is not correctly named
+            var ret = container.Resolve<AddOperation>().Invoke(1, 2);
+            Assert.AreEqual(3, ret);
+        }
+
+        public delegate void AddAction(int a, int b);
+
+        [Test]
+        public void ExecutesActionInNestedScope()
+        {
+            Assert.Fail();
+        }
+    }
+}

File Autofac/Autofac.csproj

     <Compile Include="Activators\ProvidedInstanceActivator.cs" />
     <Compile Include="Activators\BindingFlagsConstructorFinder.cs" />
     <Compile Include="Activators\ReflectionActivator.cs" />
+    <Compile Include="EntryPoints\LifetimeEntryPointGenerator.cs" />
     <Compile Include="Events\ActivatedEventArgs.cs" />
     <Compile Include="Events\ActivatingEventArgs.cs" />
     <Compile Include="GeneratedFactories\AutoGeneratedFactoryRegistrationSource.cs" />
+    <Compile Include="GeneratedFactories\DelegateTypeExtensions.cs" />
     <Compile Include="GeneratedFactories\FactoryGenerator.cs" />
     <Compile Include="Injection\AutowiringParameter.cs" />
     <Compile Include="ComponentNotRegisteredException.cs" />
     <Compile Include="Injection\AutowiringPropertyInjector.cs" />
     <Compile Include="Injection\ConstructorParameterBinding.cs" />
     <Compile Include="OpenGenerics\OpenGenericActivatorGenerator.cs" />
-    <Compile Include="Owned.cs" />
+    <Compile Include="OwnedInstances\Owned.cs" />
     <Compile Include="NamedParameter.cs" />
     <Compile Include="OwnedInstances\OwnedRegistrationSource.cs" />
     <Compile Include="PositionalParameter.cs" />

File Autofac/EntryPoints/LifetimeEntryPointGenerator.cs

+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Linq.Expressions;
+
+namespace Autofac.EntryPoints
+{
+    public class LifetimeEntryPointGenerator<TDelegate>
+    {
+        Func<ILifetimeScope, TDelegate> _entryPointGenerator;
+
+        public LifetimeEntryPointGenerator(Func<IComponentContext, IEnumerable<Parameter>, object> entryPointBinding, object scopeTag)
+        {
+            Enforce.ArgumentNotNull(entryPointBinding, "entryPointBinding");
+
+            Func<ILifetimeScope, IEnumerable<Parameter>, object> entryPoint = (ls, p) =>
+            {
+                using (var inner = ls.BeginLifetimeScope())
+                {
+                    if (scopeTag != null)
+                        inner.Tag = scopeTag;
+
+                    return entryPointBinding(inner, p);
+                }
+            };
+
+            // s => a, b, c => (drt) entryPoint(s, new PositionalParameter(0, a), ...)
+
+            var outerScopeParam = Expression.Parameter(typeof(ILifetimeScope), "s");
+            var generatorParams = new[] { outerScopeParam };
+
+            var invoke = typeof(TDelegate).GetMethod("Invoke");
+
+            // a, b, c
+            var entryPointParams = invoke
+                .GetParameters()
+                .Select(pi => Expression.Parameter(pi.ParameterType, pi.Name))
+                .ToList();
+
+            var mappedEntryPointParams = entryPointParams
+                .Select((p, i) => Expression.New(
+                        typeof(PositionalParameter).GetConstructor(new[] { typeof(int), typeof(object) }),
+                        Expression.Constant(i), Expression.Convert(p, typeof(object))))
+                .OfType<Expression>()
+                .ToArray();
+
+            var entryPointBindingParams = new Expression[] { 
+                outerScopeParam,
+                Expression.NewArrayInit(typeof(Parameter), mappedEntryPointParams)
+            };
+
+            var entryPointInvoke = entryPoint.GetType().GetMethod("Invoke");
+
+            // entryPoint(...)
+            var entryPointCall = Expression.Call(
+                Expression.Constant(entryPoint),
+                entryPointInvoke,
+                entryPointBindingParams);
+
+            // (drt)
+            var resultCast = Expression.Convert(entryPointCall, invoke.ReturnType);
+
+            // ([dps]*) => entryPoint(s, [new Parameter(name, dps)]*)
+            var entryPointExpr = Expression.Lambda(typeof(TDelegate), resultCast, entryPointParams);
+
+            // (c, p) => (
+            var generator = Expression.Lambda<Func<ILifetimeScope, TDelegate>>(entryPointExpr, generatorParams);
+
+            _entryPointGenerator = generator.Compile();
+        }
+
+        public TDelegate GenerateEntryPoint(IComponentContext context, IEnumerable<Parameter> parameters)
+        {
+            Enforce.ArgumentNotNull(context, "context");
+            Enforce.ArgumentNotNull(parameters, "parameters");
+
+            var currentScope = context.Resolve<ILifetimeScope>();
+
+            return _entryPointGenerator(currentScope);
+        }
+    }
+}

File Autofac/GeneratedFactories/AutoGeneratedFactoryRegistrationSource.cs

             Enforce.ArgumentNotNull(registeredServicesTest, "registeredServicesTest");
 
             var ts = service as TypedService;
-            if (ts != null &&
-                ts.ServiceType.IsGenericType &&
-                ts.ServiceType.GetGenericTypeDefinition().FullName.StartsWith("System.Func"))
+            if (ts != null && ts.ServiceType.IsFunction())
             {
-                var genericArgs = ts.ServiceType.GetGenericArguments();
-                var resultType = genericArgs[genericArgs.Length - 1];
+                var resultType = ts.ServiceType.FunctionReturnType();
                 var resultTypeService = new TypedService(resultType);
 
                 if (registeredServicesTest(resultTypeService))

File Autofac/GeneratedFactories/DelegateTypeExtensions.cs

+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Autofac.GeneratedFactories
+{
+    static class DelegateTypeExtensions
+    {
+        public static bool IsFunction(this Type type)
+        {
+            Enforce.ArgumentNotNull(type, "type");
+            return type.GetMethod("Invoke") != null;
+        }
+
+        public static Type FunctionReturnType(this Type type)
+        {
+            Enforce.ArgumentNotNull(type, "type");
+            var invoke = type.GetMethod("Invoke");
+            Enforce.NotNull(invoke);
+            return invoke.ReturnType;
+        }
+    }
+}

File Autofac/Owned.cs

-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using Autofac.Disposal;
-
-namespace Autofac
-{
-    public class Owned<T> : Disposable
-    {
-        readonly T _value;
-        readonly IDisposable _lifetime;
-
-        public Owned(T value, IDisposable lifetime)
-        {
-            _value = value;
-            _lifetime = lifetime;
-        }
-
-        public T Value
-        {
-            get
-            {
-                CheckNotDisposed();
-                return _value;
-            }
-        }
-
-        protected override void Dispose(bool disposing)
-        {
-            if (disposing)
-                _lifetime.Dispose();
-
-            base.Dispose(disposing);
-        }
-    }
-}

File Autofac/OwnedInstances/Owned.cs

+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Autofac.Disposal;
+
+namespace Autofac.OwnedInstances
+{
+    public class Owned<T> : Disposable
+    {
+        readonly T _value;
+        readonly IDisposable _lifetime;
+
+        public Owned(T value, IDisposable lifetime)
+        {
+            _value = value;
+            _lifetime = lifetime;
+        }
+
+        public T Value
+        {
+            get
+            {
+                CheckNotDisposed();
+                return _value;
+            }
+        }
+
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing)
+                _lifetime.Dispose();
+
+            base.Dispose(disposing);
+        }
+    }
+}

File Autofac/RegistrationExtensions.cs

 using System.Globalization;
 using Autofac.GeneratedFactories;
 using Autofac.OpenGenerics;
+using Autofac.EntryPoints;
 
 namespace Autofac
 {
             container.ComponentRegistry.AddDynamicRegistrationSource(new DynamicRegistrationSource(registrar, activatorGenerator));
             return new DynamicReflectiveRegistrar(registrar, activatorGenerator);
         }
+
+        public static void RegisterLifetimeEntryPoint<TDelegate>(this IContainer container, object scopeTag, Func<IComponentContext, IEnumerable<Parameter>, object> entryPointBinding)
+            where TDelegate : class
+        {
+            Enforce.ArgumentNotNull(container, "container");
+            Enforce.ArgumentNotNull(entryPointBinding, "entryPointBinding");
+
+            var entrypointGenerator = new LifetimeEntryPointGenerator<TDelegate>(entryPointBinding, scopeTag);
+
+            var inner = container.RegisterDelegate<TDelegate>((c, p) => entrypointGenerator.GenerateEntryPoint(c, p))
+                .InstancePerLifetimeScope();
+        }
+
+        public static void RegisterLifetimeEntryPoint<TDelegate>(this IContainer container, Func<IComponentContext, IEnumerable<Parameter>, object> entryPointBinding)
+            where TDelegate : class
+        {
+            RegisterLifetimeEntryPoint<TDelegate>(container, null, entryPointBinding);
+        }
     }
 }