diff --git a/src/CatLib.Core.Tests/CatLib/ApplicationTests.cs b/src/CatLib.Core.Tests/CatLib/ApplicationTests.cs index 6b6c39c..f619a09 100644 --- a/src/CatLib.Core.Tests/CatLib/ApplicationTests.cs +++ b/src/CatLib.Core.Tests/CatLib/ApplicationTests.cs @@ -481,6 +481,111 @@ public void TestRegisterProcessMake() app.Register(new TestRegisterProcessMakeServiceProvider()); } + public class TestExistedBoostrap : IBootstrap + { + public void Bootstrap() + { + + } + } + + [TestMethod] + [ExpectedException(typeof(LogicException))] + public void TestExistBoostrap() + { + var app = new Application(); + var boostrap = new TestExistedBoostrap(); + app.Bootstrap(boostrap, boostrap); + } + + private static int assertValue = 0; + + public class OrderAssertClass : IBootstrap, IServiceProvider + { + private readonly int assert; + public OrderAssertClass(int assert) + { + this.assert = assert; + } + + public void Bootstrap() + { + Assert.AreEqual(assert, assertValue++); + } + + /// + /// 服务提供者初始化 + /// + public void Init() + { + Bootstrap(); + } + + /// + /// 当注册服务提供者 + /// + public void Register() + { + + } + } + + public class OrderAssertClassSub : OrderAssertClass + { + public OrderAssertClassSub(int assert) + :base(assert) + { + + } + } + + [Priority(0)] + public class OrderFirstClass : IBootstrap, IServiceProvider + { + public void Bootstrap() + { + Assert.AreEqual(0, assertValue); + } + + /// + /// 服务提供者初始化 + /// + public void Init() + { + Bootstrap(); + } + + /// + /// 当注册服务提供者 + /// + public void Register() + { + + } + } + + [TestMethod] + public void TestBoostrapOrder() + { + assertValue = 0; + var app = new Application(); + app.Bootstrap(new OrderAssertClass(0), new OrderFirstClass(), new OrderAssertClass(1)); + Assert.AreEqual(2, assertValue); + } + + [TestMethod] + public void TestProviderOrder() + { + assertValue = 0; + var app = new Application(); + app.Bootstrap(); + app.Register(new OrderAssertClass(0)); + app.Register(new OrderFirstClass()); + app.Register(new OrderAssertClassSub(1)); + app.Init(); + Assert.AreEqual(2, assertValue); + } + private Application MakeApplication() { var app = new Application(); diff --git a/src/CatLib.Core.Tests/Support/Container/GivenDataTests.cs b/src/CatLib.Core.Tests/Support/Container/GivenDataTests.cs index c279dea..822075e 100644 --- a/src/CatLib.Core.Tests/Support/Container/GivenDataTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/GivenDataTests.cs @@ -52,12 +52,120 @@ public void CheckGivenIllegalValue() ExceptionAssert.Throws(() => { - givenData.Given(null); + givenData.Given(string.Empty); }); - ExceptionAssert.Throws(() => + } + + + private class TestGivenClosureClass + { + public string Name { get; set; } + public int Value { get; set; } + public TestGivenClosureClass(string name, int value = 0) { - givenData.Given(string.Empty); + Name = name; + Value = value; + } + } + + [TestMethod] + public void TestGivenClosure() + { + var container = new Container(); + container.Bind().Needs().Given(() => "hello world") + .Needs().Given(()=> 10); + + Assert.AreEqual("hello world", container.Make().Name); + Assert.AreEqual(10, container.Make().Value); + } + + [TestMethod] + [ExpectedException(typeof(LogicException))] + public void TestGivenDuplicateValue() + { + var container = new Container(); + container.Bind().Needs().Given(() => "hello world"); + container.Bind().Needs().Given(() => "ddd"); + } + + [TestMethod] + [ExpectedException(typeof(LogicException))] + public void TestGivenDuplicateValue2() + { + var container = new Container(); + container.Bind().Needs().Given(() => "hello world"); + container.Bind().Needs().Given(); + } + + [TestMethod] + [ExpectedException(typeof(LogicException))] + public void TestGivenDuplicateValue3() + { + var container = new Container(); + container.Bind().Needs().Given(); + container.Bind().Needs().Given(() => "hello world"); + } + + [TestMethod] + [ExpectedException(typeof(LogicException))] + public void TestGivenDuplicateValue4() + { + var container = new Container(); + container.Bind().Needs().Given(); + container.Bind().Needs().Given(); + } + + [TestMethod] + [ExpectedException(typeof(LogicException))] + public void TestGivenDuplicateValue5() + { + var container = new Container(); + container.Bind().Needs().Given(() => "hello world"); + container.Bind().Needs().Given(); + container.Bind().Needs().Given(); + } + + [TestMethod] + [ExpectedException(typeof(LogicException))] + public void TestGivenDuplicateValue6() + { + var container = new Container(); + container.Bind().Needs().Given(); + container.Bind().Needs().Given(() => "hello world"); + container.Bind().Needs().Given(() => "hello world"); + } + + [TestMethod] + [ExpectedException(typeof(AssertException))] + public void TestGivenClosureException() + { + var container = new Container(); + container.Bind().Needs().Given(() => + { + throw new AssertException("hello world"); }); + + container.Make(); + } + + private class TestGivenClosureAttrClass + { + [Inject] + public string Name { get; set; } + + [Inject] + public int Value { get; set; } + } + + [TestMethod] + public void TestGivenAttrClosure() + { + var container = new Container(); + container.Bind().Needs().Given(() => "hello world") + .Needs().Given(() => 10); + + Assert.AreEqual("hello world", container.Make().Name); + Assert.AreEqual(10, container.Make().Value); } } } \ No newline at end of file diff --git a/src/CatLib.Core/CatLib/Application.cs b/src/CatLib.Core/CatLib/Application.cs index 5f0e483..419be23 100644 --- a/src/CatLib.Core/CatLib/Application.cs +++ b/src/CatLib.Core/CatLib/Application.cs @@ -90,7 +90,8 @@ public enum StartProcess /// /// 服务提供者 /// - private readonly SortSet serviceProviders = new SortSet(); + private readonly List> serviceProviders = + new List>(); /// /// 注册服务提供者 @@ -198,18 +199,31 @@ public virtual void Bootstrap(params IBootstrap[] bootstraps) Trigger(ApplicationEvents.OnBootstrap, this); Process = StartProcess.Bootstrapping; - var sorting = new SortSet(); + var sorting = new List>(); + var existed = new HashSet(); foreach (var bootstrap in bootstraps) { - if (bootstrap != null) + if (bootstrap == null) { - sorting.Add(bootstrap, GetPriority(bootstrap.GetType(), nameof(IBootstrap.Bootstrap))); + continue; } + + if (existed.Contains(bootstrap)) + { + throw new LogicException($"The bootstrap already exists : {bootstrap}"); + } + + existed.Add(bootstrap); + sorting.Add(new KeyValuePair(bootstrap, + GetPriority(bootstrap.GetType(), nameof(IBootstrap.Bootstrap)))); } - foreach (var bootstrap in sorting) + sorting.Sort((left, right) => left.Value.CompareTo(right.Value)); + + foreach (var kv in sorting) { + var bootstrap = kv.Key; var allow = TriggerHalt(ApplicationEvents.Bootstrapping, bootstrap) == null; if (bootstrap != null && allow) { @@ -250,9 +264,11 @@ protected IEnumerator CoroutineInit() Trigger(ApplicationEvents.OnInit, this); Process = StartProcess.Initing; + serviceProviders.Sort((left, right) => left.Value.CompareTo(right.Value)); + foreach (var provider in serviceProviders) { - yield return InitProvider(provider); + yield return InitProvider(provider.Key); } inited = true; @@ -312,7 +328,10 @@ protected IEnumerator CoroutineRegister(IServiceProvider provider) { registering = false; } - serviceProviders.Add(provider, GetPriority(provider.GetType(), nameof(IServiceProvider.Init))); + + serviceProviders.Add( + new KeyValuePair(provider, + GetPriority(provider.GetType(), nameof(IServiceProvider.Init)))); serviceProviderTypes.Add(GetProviderBaseType(provider)); if (inited) diff --git a/src/CatLib.Core/Support/Container/Bindable.cs b/src/CatLib.Core/Support/Container/Bindable.cs index b32372c..33b7ab8 100644 --- a/src/CatLib.Core/Support/Container/Bindable.cs +++ b/src/CatLib.Core/Support/Container/Bindable.cs @@ -9,6 +9,7 @@ * Document: http://catlib.io/ */ +using System; using System.Collections.Generic; namespace CatLib @@ -34,6 +35,12 @@ public abstract class Bindable : IBindable /// private Dictionary contextual; + /// + /// 服务上下文闭包 + /// 当前服务需求某个服务时给定的闭包 + /// + private Dictionary> contextualClosure; + /// /// 同步锁 /// @@ -83,7 +90,8 @@ internal void AddContextual(string needs, string given) { contextual = new Dictionary(); } - if (contextual.ContainsKey(needs)) + if (contextual.ContainsKey(needs) + || (contextualClosure != null && contextualClosure.ContainsKey(needs))) { throw new LogicException($"Needs [{needs}] is already exist."); } @@ -91,6 +99,29 @@ internal void AddContextual(string needs, string given) } } + /// + /// 为服务增加上下文 + /// + /// 需求什么服务 + /// 给与什么服务 + internal void AddContextual(string needs, Func given) + { + lock (SyncRoot) + { + GuardIsDestroy(); + if (contextualClosure == null) + { + contextualClosure = new Dictionary>(); + } + if (contextualClosure.ContainsKey(needs) + || (contextual != null && contextual.ContainsKey(needs))) + { + throw new LogicException($"Needs [{needs}] is already exist."); + } + contextualClosure.Add(needs, given); + } + } + /// /// 获取上下文的需求关系 /// @@ -105,6 +136,20 @@ internal string GetContextual(string needs) return contextual.TryGetValue(needs, out string contextualNeeds) ? contextualNeeds : needs; } + /// + /// 获取上下文关系闭包实现 + /// + /// 需求的服务 + /// 给与的闭包 + internal Func GetContextualClosure(string needs) + { + if (contextualClosure == null) + { + return null; + } + return contextualClosure.TryGetValue(needs, out Func closure) ? closure : null; + } + /// /// 解除绑定 /// diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 4b05db4..1b47961 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -908,7 +908,7 @@ public virtual void Flush() /// /// 类型 /// 服务名 - public virtual string Type2Service(Type type) + public string Type2Service(Type type) { return type.ToString(); } @@ -1150,6 +1150,12 @@ protected virtual string GetParamNeedsService(ParameterInfo baseParam) /// 解决结果 protected virtual object ResolveAttrPrimitive(Bindable makeServiceBindData, string service, PropertyInfo baseParam) { + var contextualClosure = makeServiceBindData.GetContextualClosure(service); + if (contextualClosure != null) + { + return contextualClosure(); + } + service = makeServiceBindData.GetContextual(service); if (CanMake(service)) { @@ -1174,8 +1180,15 @@ protected virtual object ResolveAttrPrimitive(Bindable makeServiceBindData, stri /// 解决结果 protected virtual object ResloveAttrClass(Bindable makeServiceBindData, string service, PropertyInfo baseParam) { + var contextualClosure = makeServiceBindData.GetContextualClosure(service); + if (contextualClosure != null) + { + return contextualClosure(); + } + try { + // 我们不进行CanMake检查以避免一次hash return Make(makeServiceBindData.GetContextual(service)); } catch (Exception) @@ -1198,6 +1211,12 @@ protected virtual object ResloveAttrClass(Bindable makeServiceBindData, string s /// 解决结果 protected virtual object ResolvePrimitive(Bindable makeServiceBindData, string service, ParameterInfo baseParam) { + var contextualClosure = makeServiceBindData.GetContextualClosure(service); + if (contextualClosure != null) + { + return contextualClosure(); + } + service = makeServiceBindData.GetContextual(service); if (CanMake(service)) { @@ -1227,6 +1246,12 @@ protected virtual object ResolvePrimitive(Bindable makeServiceBindData, string s /// 解决结果 protected virtual object ResloveClass(Bindable makeServiceBindData, string service, ParameterInfo baseParam) { + var contextualClosure = makeServiceBindData.GetContextualClosure(service); + if (contextualClosure != null) + { + return contextualClosure(); + } + try { return Make(makeServiceBindData.GetContextual(service)); diff --git a/src/CatLib.Core/Support/Container/GivenData.cs b/src/CatLib.Core/Support/Container/GivenData.cs index ff12eb2..b2c61d2 100644 --- a/src/CatLib.Core/Support/Container/GivenData.cs +++ b/src/CatLib.Core/Support/Container/GivenData.cs @@ -9,6 +9,8 @@ * Document: http://catlib.io/ */ +using System; + namespace CatLib { /// @@ -74,5 +76,17 @@ public TReturn Given() { return Given(container.Type2Service(typeof(T))); } + + /// + /// 给与什么服务 + /// + /// 给与的服务生成闭包 + /// 服务绑定数据 + public TReturn Given(Func closure) + { + Guard.Requires(closure != null); + bindable.AddContextual(needs, closure); + return bindable as TReturn; + } } } \ No newline at end of file diff --git a/src/CatLib.Core/Support/Container/IGivenData.cs b/src/CatLib.Core/Support/Container/IGivenData.cs index ecf6f2f..c3862a7 100644 --- a/src/CatLib.Core/Support/Container/IGivenData.cs +++ b/src/CatLib.Core/Support/Container/IGivenData.cs @@ -9,6 +9,8 @@ * Document: http://catlib.io/ */ +using System; + namespace CatLib { /// @@ -29,5 +31,12 @@ public interface IGivenData /// 给与的服务名或别名 /// 服务绑定数据 TReturn Given(); + + /// + /// 给与什么服务 + /// + /// 给定的服务 + /// 服务绑定数据 + TReturn Given(Func closure); } } \ No newline at end of file