diff --git a/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj b/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj index 1a3c472..e006d96 100644 --- a/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj +++ b/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj @@ -99,6 +99,7 @@ + @@ -112,8 +113,11 @@ + + + diff --git a/src/CatLib.Core.Tests/Support/Container/BindDataTests.cs b/src/CatLib.Core.Tests/Support/Container/BindDataTests.cs index 805835c..8f8f44d 100644 --- a/src/CatLib.Core.Tests/Support/Container/BindDataTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/BindDataTests.cs @@ -177,13 +177,15 @@ public void CanOnRelease() public void CheckIllegalRelease() { var container = new Container(); - var bindData = container.Bind("CheckIllegalRelease", (app, param) => "hello world", false); + var bindData = container.Bind("CheckIllegalRelease", (app, param) => "hello world", true); ExceptionAssert.Throws(() => { bindData.OnRelease(null); }); + bindData.Unbind(); + bindData = container.Bind("CheckIllegalRelease", (app, param) => "hello world", false); ExceptionAssert.Throws(() => { bindData.OnRelease((obj) => @@ -225,33 +227,82 @@ public void TestAddOnResolvingWithExtendNoneInstance() } /// - /// 是否能追加到解决事件 + /// 检查无效的解决事件传入参数 /// [TestMethod] - public void CanAddOnResolving() + public void CheckIllegalResolving() { var container = new Container(); var bindData = new BindData(container, "CanAddOnResolving", (app, param) => "hello world", false); - bindData.OnResolving((bind, obj) => null); + ExceptionAssert.Throws(() => + { + bindData.OnResolving(null); + }); + } + + [TestMethod] + public void TestTypeMatchOnResolving() + { + var container = new Container(); + var count = 0; + container.Bind("hello", (_, __) => new ContainerHelperTests.TestTypeMatchOnResolvingClass()) + .OnResolving((instance) => + { + count++; + }).OnResolving((bindData, instance) => + { + Assert.AreNotEqual(null, bindData); + count++; + }).OnAfterResolving((instance) => + { + count++; + }).OnAfterResolving((bindData, instance) => + { + Assert.AreNotEqual(null, bindData); + count++; + }).OnAfterResolving((instance) => + { + count++; + }); + + container.Make("hello"); - var data = bindData.TriggerResolving(new Container()); - Assert.AreEqual(null, data); + Assert.AreEqual(4, count); } - /// - /// 检查无效的解决事件传入参数 - /// [TestMethod] - public void CheckIllegalResolving() + public void TestTypeMatchOnRelease() { var container = new Container(); - var bindData = new BindData(container, "CanAddOnResolving", (app, param) => "hello world", false); + var count = 0; + container.Singleton("hello", (_, __) => new ContainerHelperTests.TestTypeMatchOnResolvingClass()) + .OnRelease((instance) => + { + count++; + }).OnRelease((instance) => + { + count++; + }).OnRelease((bindData,instance) => + { + Assert.AreNotEqual(null, bindData); + count++; + }).OnRelease((bindData, instance) => + { + Assert.AreNotEqual(null, bindData); + count++; + }).OnRelease((bindData, instance) => + { + Assert.AreNotEqual(null, bindData); + count++; + }); + container.Singleton("world", (_, __) => "hello"); - ExceptionAssert.Throws(() => - { - bindData.OnResolving(null); - }); + container.Make("hello"); + + container.Release("hello"); + + Assert.AreEqual(2, count); } #endregion diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerHelperTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerHelperTests.cs index c3f2232..5c6e358 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerHelperTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerHelperTests.cs @@ -354,6 +354,143 @@ public void TestSetAlias() Assert.AreEqual("abc", container.Make()); } + public class TestOnResolvingClass + { + public string Name; + public TestOnResolvingClass() + { + + } + } + + [TestMethod] + public void TestOnResolving() + { + var container = new Container(); + container.Singleton().OnResolving((instance) => + { + var cls = (instance) as TestOnResolvingClass; + Assert.AreEqual(null, cls.Name); + cls.Name = "123"; + }); + + container.OnResolving((instance) => + { + var cls = (instance) as TestOnResolvingClass; + Assert.AreEqual("123", cls.Name); + cls.Name = "222"; + }); + + Assert.AreEqual("222", container.Make().Name); + } + + [TestMethod] + public void TestExtend() + { + var container = new Container(); + container.Extend((instance) => instance + " world"); + container.Bind(() => "hello"); + Assert.AreEqual("hello world", container.Make()); + } + + [TestMethod] + public void TestExtendContainer() + { + var container = new Container(); + container.Extend((instance, _) => + { + Assert.AreSame(container, _); + return instance + " world"; + }); + container.Bind(() => "hello"); + Assert.AreEqual("hello world", container.Make()); + } + + public interface ITypeMatchInterface + { + + } + + public class TestTypeMatchOnResolvingClass : ITypeMatchInterface + { + + } + + [TestMethod] + public void TestTypeMatchOnResolving() + { + var container = new Container(); + container.Bind("hello", (_, __) => new TestTypeMatchOnResolvingClass()); + container["world"] = "hello"; + var count = 0; + container.OnResolving((instance) => + { + count++; + }); + + container.OnResolving((bindData, instance) => + { + Assert.AreNotEqual(null, bindData); + count++; + }); + + container.OnAfterResolving((instance) => + { + count++; + }); + + container.OnAfterResolving((bindData,instance) => + { + Assert.AreNotEqual(null, bindData); + count++; + }); + + container.Make("hello"); + container.Make("world"); + + Assert.AreEqual(4, count); + } + + [TestMethod] + public void TestTypeMatchOnRelease() + { + var container = new Container(); + container.Singleton("hello", (_, __) => new TestTypeMatchOnResolvingClass()); + container.Singleton("world", (_, __) => "hello"); + var count = 0; + var stringCount = 0; + container.OnRelease((instance) => + { + count++; + }); + + container.OnRelease((bindData, instance) => + { + Assert.AreNotEqual(null, bindData); + count++; + }); + + container.OnRelease((instance) => + { + stringCount++; + }); + + container.OnRelease((bindData, instance) => + { + Assert.AreNotEqual(null, bindData); + stringCount++; + }); + + container.Make("hello"); + container.Make("world"); + + container.Release("hello"); + container.Release("world"); + + Assert.AreEqual(2, count); + Assert.AreEqual(2, stringCount); + } + /// /// 生成容器 /// diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs index e8a11f4..a1019aa 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs @@ -1043,47 +1043,6 @@ public void CheckIllegalMake() }); } - /// - /// 解决器是否有效 - /// - [TestMethod] - public void CanMakeWithResolve() - { - var container = MakeContainer(); - var bind = container.Bind(); - - bind.OnResolving((bindData, obj) => "local resolve"); - container.OnResolving((bindData, obj) => obj + " global resolve"); - var isTrigger = false; - container.OnResolving((obj) => isTrigger = true); - - var result = container.Make(container.Type2Service(typeof(MakeTestClassDependency))); - - Assert.AreEqual(true, isTrigger); - Assert.AreEqual("local resolve global resolve", result); - } - - /// - /// 给与了错误的解决器,导致不正确的返回值 - /// - [TestMethod] - public void CheckMakeWithErrorResolve() - { - var container = MakeContainer(); - var bind = container.Bind(); - container.Bind().Alias("AliasName"); - var bind2 = container.Bind().Alias("AliasNameRequired"); - - bind.OnResolving((bindData, obj) => "local resolve"); - container.OnResolving((bindData, obj) => obj + " global resolve"); - bind2.OnResolving((bindData, obj) => "bind2"); - - ExceptionAssert.Throws(() => - { - container.Make(container.Type2Service(typeof(MakeTestClass))); - }); - } - /// /// 参数注入标记测试类 /// @@ -1808,7 +1767,6 @@ public void OnResolvingExistsObject() container.OnResolving((bind, obj) => { isCall = true; - return obj; }); Assert.AreEqual(false, isCall); @@ -2334,14 +2292,15 @@ public void TestInstanceAndDecorator() var container = new Container(); var oldObject = new object(); object newObject = null; - container.OnResolving((bindData, obj) => + container.Extend("Hello", (instance, c) => { + Console.WriteLine("new"); return newObject = new object(); }); - container.Instance("Hello", oldObject); - - Assert.AreSame(newObject, container["Hello"]); + container.Bind("Hello", (_, __) => oldObject); + var ins = container["Hello"]; + Assert.AreSame(newObject, ins); } [TestMethod] @@ -2527,6 +2486,187 @@ public void TestCannotWatch() { } + + [TestMethod] + public void TestExtend() + { + var container = new Container(); + container.Bind("hello", (_, __) => "hello"); + container.Extend("hello", (instance, c) => instance + " world"); + + Assert.AreEqual("hello world", container["hello"]); + } + + [TestMethod] + public void TestMultExtend() + { + var container = new Container(); + container.Bind("hello", (_, __) => "hello"); + container.Extend("hello", (instance, c) => instance + " world"); + container.Extend("hello", (instance, c) => instance + " miaomiao"); + + Assert.AreEqual("hello world miaomiao", container["hello"]); + } + + [TestMethod] + public void TestClearExtend() + { + var container = new Container(); + container.Bind("hello", (_, __) => "hello"); + container.Extend("hello", (instance, c) => instance + " world"); + container.Extend("hello", (instance, c) => instance + " miaomiao"); + + container.Bind("world", (_, __) => "hello"); + container.Extend("world", (instance, c) => instance + " world"); + container.Extend("world", (instance, c) => instance + " miaomiao"); + + Assert.AreEqual("hello world miaomiao", container["hello"]); + Assert.AreEqual("hello world miaomiao", container["world"]); + + container.ClearExtenders("hello"); + + Assert.AreEqual("hello", container["hello"]); + Assert.AreEqual("hello world miaomiao", container["world"]); + } + + [TestMethod] + public void TestClearExtendNotUse() + { + var container = new Container(); + container.Bind("hello", (_, __) => "hello"); + container.Extend("hello", (instance, c) => instance + " world"); + container.Extend("hello", (instance, c) => instance + " miaomiao"); + container.ClearExtenders("hello"); + Assert.AreEqual("hello", container["hello"]); + } + + [TestMethod] + public void TestExtendSingle() + { + var container = new Container(); + container.Singleton("hello", (_, __) => "hello"); + container.Extend("hello", (instance, c) => instance + " world"); + Assert.AreEqual("hello world", container["hello"]); + container.Extend("hello", (instance, c) => instance + " miaomiao"); + Assert.AreEqual("hello world miaomiao", container["hello"]); + + container.Release("hello"); + Assert.AreEqual("hello world", container["hello"]); + } + + [TestMethod] + public void TestIsResolvedExtend() + { + var container = new Container(); + container.Singleton("hello", (_, __) => "hello"); + container.Make("hello"); + container.Release("hello"); + + var data = ""; + container.OnRebound("hello", (instance) => + { + data = instance.ToString(); + }); + container.Extend("hello", (instance, c) => instance + " world"); + + Assert.AreEqual("hello world", data); + } + + public class TestExtendGivenMismatchedTypeClass + { + public TestExtendGivenMismatchedTypeClass(IContainer container) + { + + } + } + + [TestMethod] + [ExpectedException(typeof(UnresolvableException))] + public void TestExtendGivenMismatchedType() + { + var container = new Container(); + container.Singleton(() => container); + container.Singleton(); + container.Extend((instance) => "123"); + container.Make(); + } + + [TestMethod] + public void TestThisSet() + { + var container = new Container(); + container["hello"] = "world"; + Assert.AreEqual("world", container.Make("hello")); + } + + [TestMethod] + public void TestMultThisSet() + { + var container = new Container(); + container["hello"] = "world"; + container["world"] = "hello"; + Assert.AreEqual("world", container.Make("hello")); + Assert.AreEqual("hello", container.Make("world")); + } + + [TestMethod] + public void TestExistsThisSet() + { + var container = new Container(); + container["hello"] = "world"; + Assert.AreEqual("world", container.Make("hello")); + container["hello"] = 123; + Assert.AreEqual(123, container.Make("hello")); + } + + [TestMethod] + public void TestOnAfterResolving() + { + var container = new Container(); + var val = 0; + container.OnAfterResolving((_) => + { + Assert.AreEqual(10, val); + val = 20; + }); + container.OnAfterResolving((_,__) => + { + Assert.AreEqual(20, val); + val = 30; + }); + container.OnResolving((_, __) => + { + Assert.AreEqual(0, val); + val = 10; + }); + + container["hello"] = "hello"; + Assert.AreEqual("hello", container["hello"]); + Assert.AreEqual(30, val); + } + + [TestMethod] + public void TestOnAfterResolvingLocal() + { + var container = new Container(); + var val = 0; + container.Bind("hello", (_, __) => "world").OnAfterResolving(() => + { + Assert.AreEqual(10, val); + val = 20; + }).OnAfterResolving((_) => + { + Assert.AreEqual(20, val); + val = 30; + }).OnResolving(() => + { + Assert.AreEqual(0, val); + val = 10; + }); + + Assert.AreEqual("world", container["hello"]); + Assert.AreEqual(30, val); + } #endregion /// diff --git a/src/CatLib.Core/CatLib.Core.csproj b/src/CatLib.Core/CatLib.Core.csproj index 141ccc7..9604ade 100644 --- a/src/CatLib.Core/CatLib.Core.csproj +++ b/src/CatLib.Core/CatLib.Core.csproj @@ -82,6 +82,7 @@ + diff --git a/src/CatLib.Core/CatLib/App.cs b/src/CatLib.Core/CatLib/App.cs index eed05e7..97ed474 100644 --- a/src/CatLib.Core/CatLib/App.cs +++ b/src/CatLib.Core/CatLib/App.cs @@ -591,6 +591,30 @@ public static Func Factory(string service) return Handler.Factory(service); } + /// + /// 扩展容器中的服务 + /// 允许在服务构建的过程中配置或者替换服务 + /// 如果服务已经被构建,拓展会立即生效。 + /// + /// 服务名或别名 + /// 闭包 + public static void Extend(Func closure) + { + Handler.Extend(closure); + } + + /// + /// 扩展容器中的服务 + /// 允许在服务构建的过程中配置或者替换服务 + /// 如果服务已经被构建,拓展会立即生效。 + /// + /// 服务名或别名 + /// 闭包 + public static void Extend(Func closure) + { + Handler.Extend(closure); + } + /// /// 为服务设定一个别名 /// @@ -605,11 +629,11 @@ public static IContainer Alias(string alias, string service) /// /// 当服务被解决时触发的事件 /// - /// 回调函数 + /// 闭包函数 /// 当前容器实例 - public static IContainer OnResolving(Func func) + public static IContainer OnResolving(Action closure) { - return Handler.OnResolving(func); + return Handler.OnResolving(closure); } /// diff --git a/src/CatLib.Core/CatLib/Application.cs b/src/CatLib.Core/CatLib/Application.cs index 5da6c5b..5f13edb 100644 --- a/src/CatLib.Core/CatLib/Application.cs +++ b/src/CatLib.Core/CatLib/Application.cs @@ -233,7 +233,7 @@ public virtual void Init() /// /// 初始化 /// - /// 没有调用Bootstrap(...)就尝试初始化时触发 + /// 没有调用Bootstrap(...)就尝试初始化时触发 protected IEnumerator CoroutineInit() { if (!bootstrapped) @@ -267,7 +267,7 @@ protected IEnumerator CoroutineInit() /// 注册服务提供者 /// /// 注册服务提供者 - /// 服务提供者被重复注册时触发 + /// 服务提供者被重复注册时触发 public virtual void Register(IServiceProvider provider) { StartCoroutine(CoroutineRegister(provider)); @@ -277,14 +277,14 @@ public virtual void Register(IServiceProvider provider) /// 注册服务提供者 /// /// 注册服务提供者 - /// 服务提供者被重复注册时触发 + /// 服务提供者被重复注册时触发 protected IEnumerator CoroutineRegister(IServiceProvider provider) { Guard.Requires(provider != null); if (IsRegisted(provider)) { - throw new RuntimeException($"Provider [{provider.GetType()}] is already register."); + throw new LogicException($"Provider [{provider.GetType()}] is already register."); } if (Process == StartProcess.Initing) diff --git a/src/CatLib.Core/Support/Container/BindData.cs b/src/CatLib.Core/Support/Container/BindData.cs index 1c30d27..566855c 100644 --- a/src/CatLib.Core/Support/Container/BindData.cs +++ b/src/CatLib.Core/Support/Container/BindData.cs @@ -32,7 +32,12 @@ internal sealed class BindData : Bindable, IBindData /// /// 服务构造修饰器 /// - private List> resolving; + private List> resolving; + + /// + /// 在服务构建修饰器之后的修饰器 + /// + private List> afterResolving; /// /// 服务构造修饰器 @@ -98,44 +103,39 @@ public IBindData Tag(string tag) /// /// 解决服务时触发的回调 /// - /// 解决事件 + /// 解决事件 /// 服务绑定数据 - public IBindData OnResolving(Func func) + public IBindData OnResolving(Action closure) { - Guard.NotNull(func, nameof(func)); - lock (SyncRoot) - { - GuardIsDestroy(); - if (resolving == null) - { - resolving = new List>(); - } - resolving.Add(func); - } + AddClosure(closure, ref resolving); + return this; + } + + /// + /// 解决服务时事件之后的回调 + /// + /// 解决事件 + /// 服务绑定数据 + public IBindData OnAfterResolving(Action closure) + { + AddClosure(closure, ref afterResolving); return this; } /// /// 当静态服务被释放时 /// - /// 处理事件 + /// 处理事件 /// 服务绑定数据 - public IBindData OnRelease(Action action) + public IBindData OnRelease(Action closure) { - Guard.NotNull(action, nameof(action)); if (!IsStatic) { - throw new RuntimeException($"Service [{Service}] is not Singleton(Static) Bind , Can not call {nameof(OnRelease)}()."); - } - lock (SyncRoot) - { - GuardIsDestroy(); - if (release == null) - { - release = new List>(); - } - release.Add(action); + throw new LogicException( + $"Service [{Service}] is not Singleton(Static) Bind , Can not call {nameof(OnRelease)}()."); } + + AddClosure(closure, ref release); return this; } @@ -150,35 +150,52 @@ protected override void ReleaseBind() /// /// 执行服务修饰器 /// - /// 服务实例 - /// 修饰后的服务实例 - internal object TriggerResolving(object obj) + /// 服务实例 + /// 服务实例 + internal object TriggerResolving(object instance) { - if (resolving == null) - { - return obj; - } - foreach (var func in resolving) - { - obj = func.Invoke(this, obj); - } - return obj; + return Container.Trigger(this, instance, resolving); + } + + /// + /// 执行服务修饰器之后的回调 + /// + /// 服务实例 + /// 服务实例 + internal object TriggerAfterResolving(object instance) + { + return Container.Trigger(this, instance, afterResolving); } /// /// 执行服务释放处理器 /// - /// 服务实例 - internal void TriggerRelease(object obj) + /// 服务实例 + /// 服务实例 + internal object TriggerRelease(object instance) { - if (release == null) - { - return; - } + return Container.Trigger(this, instance, release); + } + + /// + /// 增加一个事件 + /// + /// 闭包 + /// 事件列表 + private void AddClosure(Action closure, ref List> list) + { + Guard.NotNull(closure, nameof(closure)); - foreach (var action in release) + lock (SyncRoot) { - action.Invoke(this, obj); + GuardIsDestroy(); + + if (list == null) + { + list = new List>(); + } + + list.Add(closure); } } } diff --git a/src/CatLib.Core/Support/Container/BindDataExtend.cs b/src/CatLib.Core/Support/Container/BindDataExtend.cs index c121d3f..da4fa11 100644 --- a/src/CatLib.Core/Support/Container/BindDataExtend.cs +++ b/src/CatLib.Core/Support/Container/BindDataExtend.cs @@ -30,7 +30,44 @@ public static IBindData OnResolving(this IBindData bindData, Action acti return bindData.OnResolving((_, instance) => { action(instance); - return instance; + }); + } + + /// + /// 解决服务时触发的回调 + /// + /// 指定的类型 + /// 绑定数据 + /// 闭包 + /// 服务绑定数据 + public static IBindData OnResolving(this IBindData bindData, Action closure) + { + Guard.Requires(closure != null); + return bindData.OnResolving((_, instance) => + { + if (instance is T) + { + closure((T)instance); + } + }); + } + + /// + /// 解决服务时触发的回调 + /// + /// 指定的类型 + /// 绑定数据 + /// 闭包 + /// 服务绑定数据 + public static IBindData OnResolving(this IBindData bindData, Action closure) + { + Guard.Requires(closure != null); + return bindData.OnResolving((bind, instance) => + { + if (instance is T) + { + closure(bind, (T)instance); + } }); } @@ -46,7 +83,72 @@ public static IBindData OnResolving(this IBindData bindData, Action action) return bindData.OnResolving((_, instance) => { action(); - return instance; + }); + } + + /// + /// 解决服务事件之后的回调 + /// + /// 绑定数据 + /// 解决事件 + /// 服务绑定数据 + public static IBindData OnAfterResolving(this IBindData bindData, Action action) + { + Guard.Requires(action != null); + return bindData.OnAfterResolving((_, instance) => + { + action(instance); + }); + } + + /// + /// 解决服务事件之后的回调 + /// + /// 绑定数据 + /// 解决事件 + /// 服务绑定数据 + public static IBindData OnAfterResolving(this IBindData bindData, Action closure) + { + Guard.Requires(closure != null); + return bindData.OnAfterResolving((_, instance) => + { + if (instance is T) + { + closure((T)instance); + } + }); + } + + /// + /// 解决服务事件之后的回调 + /// + /// 绑定数据 + /// 解决事件 + /// 服务绑定数据 + public static IBindData OnAfterResolving(this IBindData bindData, Action closure) + { + Guard.Requires(closure != null); + return bindData.OnAfterResolving((bind, instance) => + { + if (instance is T) + { + closure(bind, (T)instance); + } + }); + } + + /// + /// 解决服务事件之后的回调 + /// + /// 绑定数据 + /// 解决事件 + /// 服务绑定数据 + public static IBindData OnAfterResolving(this IBindData bindData, Action action) + { + Guard.Requires(action != null); + return bindData.OnAfterResolving((_, instance) => + { + action(); }); } @@ -65,6 +167,42 @@ public static IBindData OnRelease(this IBindData bindData, Action action }); } + /// + /// 当静态服务被释放时 + /// + /// 绑定数据 + /// 处理事件 + /// 服务绑定数据 + public static IBindData OnRelease(this IBindData bindData, Action closure) + { + Guard.Requires(closure != null); + return bindData.OnRelease((_, instance) => + { + if (instance is T) + { + closure((T)instance); + } + }); + } + + /// + /// 当静态服务被释放时 + /// + /// 绑定数据 + /// 处理事件 + /// 服务绑定数据 + public static IBindData OnRelease(this IBindData bindData, Action closure) + { + Guard.Requires(closure != null); + return bindData.OnRelease((bind, instance) => + { + if (instance is T) + { + closure(bind, (T)instance); + } + }); + } + /// /// 当静态服务被释放时 /// diff --git a/src/CatLib.Core/Support/Container/Bindable.cs b/src/CatLib.Core/Support/Container/Bindable.cs index fd794d6..b32372c 100644 --- a/src/CatLib.Core/Support/Container/Bindable.cs +++ b/src/CatLib.Core/Support/Container/Bindable.cs @@ -21,7 +21,7 @@ public abstract class Bindable : IBindable /// /// 当前绑定的名字 /// - public string Service { get; private set; } + public string Service { get; } /// /// 父级容器 @@ -85,7 +85,7 @@ internal void AddContextual(string needs, string given) } if (contextual.ContainsKey(needs)) { - throw new RuntimeException($"Needs [{needs}] is already exist."); + throw new LogicException($"Needs [{needs}] is already exist."); } contextual.Add(needs, given); } @@ -117,7 +117,7 @@ protected void GuardIsDestroy() { if (isDestroy) { - throw new RuntimeException("Current bind has be mark Destroy."); + throw new LogicException("Current bind has be mark Destroy."); } } } diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index fae1239..3717109 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -54,13 +54,23 @@ public class Container : IContainer /// /// 服务构建时的修饰器 /// - private readonly List> resolving; + private readonly List> resolving; + + /// + /// 在服务构建修饰器之后的修饰器 + /// + private readonly List> afterResloving; /// /// 静态服务释放时的修饰器 /// private readonly List> release; + /// + /// 全局服务扩展方法 + /// + private readonly Dictionary>> extenders; + /// /// 类型查询回调 /// 当类型无法被解决时会尝试去开发者提供的查询器中查询类型 @@ -125,7 +135,7 @@ public class Container : IContainer /// /// 服务禁用字符 /// - private static readonly char[] ServiceBanChars = { '@', ':' ,'$'}; + private static readonly char[] ServiceBanChars = { '@', ':', '$' }; /// /// 构造一个容器 @@ -140,8 +150,10 @@ public Container(int prime = 64) instances = new Dictionary(prime * 4); instancesReverse = new Dictionary(prime * 4); binds = new Dictionary(prime * 4); - resolving = new List>((int)(prime * 0.25)); + resolving = new List>((int)(prime * 0.25)); + afterResloving = new List>((int)(prime * 0.25)); release = new List>((int)(prime * 0.25)); + extenders = new Dictionary>>((int)(prime * 0.25)); resolved = new HashSet(); findType = new SortSet, int>(); findTypeCache = new Dictionary(prime * 4); @@ -187,7 +199,7 @@ public void Tag(string tag, params string[] service) /// /// 标记名 /// 将会返回标记所对应的所有服务实例 - /// 不存在 + /// 不存在 /// null或者空字符串 public object[] Tagged(string tag) { @@ -196,7 +208,7 @@ public object[] Tagged(string tag) { if (!tags.TryGetValue(tag, out List services)) { - throw new RuntimeException($"Tag [{tag}] is not exist."); + throw new LogicException($"Tag [{tag}] is not exist."); } var result = new object[services.Count]; @@ -315,7 +327,7 @@ public bool IsAlias(string name) /// 别名 /// 映射到的服务名 /// 当前容器对象 - /// 别名冲突或者的绑定与实例都不存在 + /// 别名冲突或者的绑定与实例都不存在 /// ,null或者空字符串 public IContainer Alias(string alias, string service) { @@ -324,7 +336,7 @@ public IContainer Alias(string alias, string service) if (alias == service) { - throw new RuntimeException($"Alias is same as service name: [{alias}]."); + throw new LogicException($"Alias is same as service name: [{alias}]."); } alias = FormatService(alias); @@ -335,7 +347,7 @@ public IContainer Alias(string alias, string service) GuardFlushing(); if (aliases.ContainsKey(alias)) { - throw new RuntimeException($"Alias [{alias}] is already exists."); + throw new LogicException($"Alias [{alias}] is already exists."); } if (!binds.ContainsKey(service) && !instances.ContainsKey(service)) @@ -408,7 +420,7 @@ public IBindData Bind(string service, Type concrete, bool isStatic) Guard.NotNull(concrete, nameof(concrete)); if (IsUnableType(concrete)) { - throw new RuntimeException($"Bind type [{concrete}] can not built"); + throw new LogicException($"Bind type [{concrete}] can not built"); } return Bind(service, WrapperTypeBuilder(service, concrete), isStatic); } @@ -420,7 +432,7 @@ public IBindData Bind(string service, Type concrete, bool isStatic) /// 服务实现 /// 服务是否静态化 /// 服务绑定数据 - /// 绑定冲突 + /// 绑定冲突 /// null public IBindData Bind(string service, Func concrete, bool isStatic) { @@ -435,17 +447,17 @@ public IBindData Bind(string service, Func concret if (binds.ContainsKey(service)) { - throw new RuntimeException($"Bind [{service}] already exists."); + throw new LogicException($"Bind [{service}] already exists."); } if (instances.ContainsKey(service)) { - throw new RuntimeException($"Instances [{service}] is already exists."); + throw new LogicException($"Instances [{service}] is already exists."); } if (aliases.ContainsKey(service)) { - throw new RuntimeException($"Aliase [{service}] is already exists."); + throw new LogicException($"Aliase [{service}] is already exists."); } var bindData = new BindData(this, service, concrete, isStatic); @@ -544,7 +556,7 @@ public object Call(object target, MethodInfo methodInfo, params object[] userPar /// 服务名或别名 /// 用户传入的构造参数 /// null或者空字符串 - /// 出现循环依赖 + /// 出现循环依赖 /// 服务实例,如果构造失败那么返回null public object Make(string service, params object[] userParams) { @@ -556,7 +568,22 @@ public object Make(string service, params object[] userParams) /// /// 服务名或者别名 /// 服务实例,如果构造失败那么返回null - public object this[string service] => Make(service); + public object this[string service] + { + get => Make(service); + set + { + lock (syncRoot) + { + var bind = GetBind(service); + if (bind != null) + { + Unbind(bind); + } + Bind(service, (_, __) => value, false); + } + } + } /// /// 获取一个回调,当执行回调可以生成指定的服务 @@ -569,13 +596,83 @@ public Func Factory(string service, params object[] userParams) return () => Make(service, userParams); } + /// + /// 扩展容器中的服务 + /// 允许在服务构建的过程中配置或者替换服务 + /// 如果服务已经被构建,拓展会立即生效。 + /// + /// 服务名或别名 + /// 闭包 + public void Extend(string service, Func closure) + { + Guard.NotEmptyOrNull(service, nameof(service)); + Guard.Requires(closure != null); + + lock (syncRoot) + { + GuardFlushing(); + service = AliasToService(service); + + if (instances.TryGetValue(service, out object instance)) + { + // 如果实例已经存在那么,那么应用扩展。 + // 扩展将不再被添加到永久扩展列表 + var old = instance; + instances[service] = instance = closure(instance, this); + + if (!old.Equals(instance)) + { + instancesReverse.Remove(old); + instancesReverse.Add(instance, service); + } + + TriggerOnRebound(service, instance); + return; + } + + if (!extenders.TryGetValue(service, out List> extender)) + { + extenders[service] = extender = new List>(); + } + + extender.Add(closure); + + if (IsResolved(service)) + { + TriggerOnRebound(service); + } + } + } + + /// + /// 移除指定服务的全部扩展 + /// + /// 服务名或别名 + public void ClearExtenders(string service) + { + lock (syncRoot) + { + GuardFlushing(); + service = AliasToService(service); + extenders.Remove(service); + + if (!IsResolved(service)) + { + return; + } + + Release(service); + TriggerOnRebound(service); + } + } + /// /// 静态化一个服务,实例值会经过解决修饰器 /// /// 服务名或别名 /// 服务实例,null也是合法的实例值 /// null或者空字符串 - /// 的服务在绑定设置中不是静态的 + /// 的服务在绑定设置中不是静态的 /// 被修饰器处理后的新的实例 public object Instance(string service, object instance) { @@ -593,16 +690,15 @@ public object Instance(string service, object instance) { if (!bindData.IsStatic) { - throw new RuntimeException($"Service [{service}] is not Singleton(Static) Bind."); + throw new LogicException($"Service [{service}] is not Singleton(Static) Bind."); } - instance = ((BindData)bindData).TriggerResolving(instance); } else { bindData = MakeEmptyBindData(service); } - instance = TriggerOnResolving(bindData, instance); + instance = TriggerOnResolving((BindData)bindData, instance); if (instance != null && instancesReverse.TryGetValue(instance, out string realService) @@ -692,37 +788,40 @@ public IContainer OnFindType(Func finder, int priority = int.MaxVa /// /// 当静态服务被释放时 /// - /// 处理释放时的回调 + /// 处理释放时的回调 /// 当前容器实例 - public IContainer OnRelease(Action callback) + public IContainer OnRelease(Action closure) { - Guard.NotNull(callback, nameof(callback)); - lock (syncRoot) - { - GuardFlushing(); - release.Add(callback); - } + AddClosure(closure, release); return this; } /// /// 当服务被解决时,生成的服务会经过注册的回调函数 /// - /// 回调函数 + /// 回调函数 /// 当前容器对象 - public IContainer OnResolving(Func callback) + public IContainer OnResolving(Action closure) { - Guard.NotNull(callback, nameof(callback)); - lock (syncRoot) - { - GuardFlushing(); - resolving.Add(callback); - } + AddClosure(closure, resolving); return this; } /// - /// 当一个已经被解决的服务发生重定义时触发 + /// 解决服务时事件之后的回调 + /// + /// 解决事件 + /// 服务绑定数据 + public IContainer OnAfterResolving(Action closure) + { + AddClosure(closure, afterResloving); + return this; + } + + /// + /// 关注指定的服务,当服务触发重定义时调用指定对象的指定方法 + /// 调用是以依赖注入的形式进行的 + /// 服务的新建(第一次解决服务)操作并不会触发重定义 /// /// 服务名 /// 回调 @@ -745,34 +844,12 @@ public IContainer OnRebound(string service, Action callback) { rebound[service] = list = new List>(); } + list.Add(callback); } return this; } - /// - /// 关注指定的服务,当服务触发重定义时调用指定对象的指定方法 - /// 调用是以依赖注入的形式进行的 - /// 服务的新建(第一次解决服务)操作并不会触发重定义 - /// - /// 关注的服务名 - /// 当服务发生重定义时调用的目标 - /// 方法信息 - public void Watch(string service, object target, MethodInfo methodInfo) - { - Guard.Requires(methodInfo != null); - - if (!methodInfo.IsStatic) - { - Guard.Requires(target != null); - } - - OnRebound(service, (instance) => - { - Call(target, methodInfo, instance); - }); - } - /// /// 解除绑定服务 /// @@ -785,7 +862,7 @@ public void Unbind(string service) } /// - /// 清空容器的所有实例,绑定,别名,标签,解决器 + /// 清空容器的所有实例,绑定,别名,标签,解决器,方法容器, 扩展 /// public virtual void Flush() { @@ -808,6 +885,7 @@ public virtual void Flush() binds.Clear(); resolving.Clear(); release.Clear(); + extenders.Clear(); resolved.Clear(); findType.Clear(); findTypeCache.Clear(); @@ -843,6 +921,7 @@ internal void Unbind(IBindable bindable) { lock (syncRoot) { + GuardFlushing(); Release(bindable.Service); if (aliasesReverse.TryGetValue(bindable.Service, out List serviceList)) { @@ -882,7 +961,7 @@ public void Flash(Action callback, params KeyValuePair[] service // 所以我们抛出一个异常来终止该操作。 if (HasBind(service.Key)) { - throw new RuntimeException( + throw new LogicException( $"Flash service [{service.Key}] name has be used for {nameof(Bind)} or {nameof(Alias)}."); } } @@ -1106,7 +1185,6 @@ protected virtual object ResloveAttrClass(Bindable makeServiceBindData, string s { return result; } - throw; } } @@ -1204,7 +1282,7 @@ protected virtual object SpeculationServiceByParamName(Bindable makeServiceBindD /// 变量标签 protected virtual char[] GetVariableTags() { - return new [] {'$', '@'}; + return new[] { '$', '@' }; } /// @@ -1276,11 +1354,11 @@ protected virtual UnresolvableException MakeUnresolvablePrimitiveException(strin /// /// 当前服务名 /// 运行时异常 - protected virtual RuntimeException MakeCircularDependencyException(string service) + protected virtual LogicException MakeCircularDependencyException(string service) { var message = $"Circular dependency detected while for [{service}]."; message += GetBuildStackDebugMessage(); - return new RuntimeException(message); + return new LogicException(message); } /// @@ -1312,7 +1390,7 @@ protected virtual void GuardUserParamsCount(int count) { if (count > 255) { - throw new RuntimeException("Too many parameters , must be less or equal than 255"); + throw new LogicException("Too many parameters , must be less or equal than 255"); } } @@ -1359,7 +1437,7 @@ protected virtual Type SpeculatedServiceType(string service) /// 服务绑定数据 /// 服务实例 /// 服务实例 - /// 属性是必须的或者注入类型和需求类型不一致 + /// 属性是必须的或者注入类型和需求类型不一致 protected virtual void AttributeInject(Bindable makeServiceBindData, object makeServiceInstance) { if (makeServiceInstance == null) @@ -1465,7 +1543,7 @@ protected virtual Func GetParamsMatcher(ref object[] user /// 服务实例的参数信息 /// 输入的构造参数列表 /// 服务所需参数的解决结果 - /// 生成的实例类型和需求类型不一致 + /// 生成的实例类型和需求类型不一致 protected virtual object[] GetDependencies(Bindable makeServiceBindData, ParameterInfo[] baseParams, object[] userParams) { if (baseParams.Length <= 0) @@ -1627,29 +1705,58 @@ private string AliasToService(string service) /// 触发全局解决修饰器 /// /// 服务绑定数据 - /// 服务实例 + /// 服务实例 /// 被修饰器修饰后的服务实例 - private object TriggerOnResolving(IBindData bindData, object obj) + private object TriggerOnResolving(BindData bindData, object instance) { - foreach (var func in resolving) - { - obj = func(bindData, obj); - } - return obj; + instance = bindData.TriggerResolving(instance); + instance = Trigger(bindData, instance, resolving); + return TriggerOnAfterResolving(bindData, instance); + } + + /// + /// 触发全局解决修饰器之后的修饰器回调 + /// + /// 服务绑定数据 + /// 服务实例 + /// 被修饰器修饰后的服务实例 + private object TriggerOnAfterResolving(BindData bindData, object instance) + { + instance = bindData.TriggerAfterResolving(instance); + return Trigger(bindData, instance, afterResloving); } /// /// 触发全局释放修饰器 /// /// 服务绑定数据 - /// 服务实例 + /// 服务实例 /// 被修饰器修饰后的服务实例 - private void TriggerOnRelease(IBindData bindData, object obj) + private object TriggerOnRelease(IBindData bindData, object instance) + { + return Trigger(bindData, instance, release); + } + + /// + /// 触发指定的事件列表 + /// + /// 服务绑定数据 + /// 服务实例 + /// 事件列表 + /// 服务实例 + internal object Trigger(IBindData bindData, object instance, List> list) { - foreach (var action in release) + if (list == null) + { + return instance; + } + + foreach (var closure in list) { - action.Invoke(bindData, obj); + closure(bindData, instance); } + + return instance; } /// @@ -1742,7 +1849,7 @@ private BindData MakeEmptyBindData(string service) /// 用户传入的构造参数 /// 服务实例,如果构造失败那么返回null /// null或者空字符串 - /// 出现循环依赖 + /// 出现循环依赖 /// 无法解决服务 /// 服务实例 private object Resolve(string service, params object[] userParams) @@ -1768,9 +1875,21 @@ private object Resolve(string service, params object[] userParams) try { var bindData = GetBindFillable(service); - var result = Inject(bindData, Build(bindData, userParams)); + + // 我们将要开始构建服务实例, + // 对于构建的服务我们会尝试进行依赖注入。 + instance = Build(bindData, userParams); + + // 如果我们为指定的服务定义了扩展器,那么我们需要依次执行扩展器, + // 并允许扩展器来修改或者覆盖原始的服务。 + instance = Extend(service, instance); + + instance = bindData.IsStatic + ? Instance(bindData.Service, instance) + : TriggerOnResolving(bindData, instance); + resolved.Add(bindData.Service); - return result; + return instance; } finally { @@ -1780,22 +1899,39 @@ private object Resolve(string service, params object[] userParams) } } + /// + /// 为服务进行扩展 + /// + /// 服务名 + /// 服务实例 + /// 扩展后的服务 + private object Extend(string service, object instance) + { + if (!extenders.TryGetValue(service, out List> list)) + { + return instance; + } + + foreach (var extender in list) + { + instance = extender(instance, this); + } + + return instance; + } + /// /// 为对象进行依赖注入 /// /// 绑定数据 /// 对象实例 /// 注入完成的对象 - private object Inject(BindData bindData, object instance) + private object Inject(Bindable bindData, object instance) { GuardResolveInstance(instance, bindData.Service); AttributeInject(bindData, instance); - instance = bindData.IsStatic - ? Instance(bindData.Service, instance) - : TriggerOnResolving(bindData, bindData.TriggerResolving(instance)); - return instance; } @@ -1807,10 +1943,12 @@ private object Inject(BindData bindData, object instance) /// 服务实例 private object Build(BindData makeServiceBindData, object[] userParams) { - return makeServiceBindData.Concrete != null + var instance = makeServiceBindData.Concrete != null ? makeServiceBindData.Concrete(this, userParams) : CreateInstance(makeServiceBindData, SpeculatedServiceType(makeServiceBindData.Service), userParams); + + return Inject(makeServiceBindData, instance); } /// @@ -1900,5 +2038,21 @@ private Func MakeParamsMatcher(IParams[] tables) return null; }; } + + /// + /// 增加一个闭包到指定的列表 + /// + /// 闭包 + /// 指定的列表 + private void AddClosure(Action closure, List> list) + { + Guard.NotNull(closure, nameof(closure)); + + lock (syncRoot) + { + GuardFlushing(); + list.Add(closure); + } + } } } \ No newline at end of file diff --git a/src/CatLib.Core/Support/Container/ContainerExtend.cs b/src/CatLib.Core/Support/Container/ContainerExtend.cs index b603aa1..ad935b7 100644 --- a/src/CatLib.Core/Support/Container/ContainerExtend.cs +++ b/src/CatLib.Core/Support/Container/ContainerExtend.cs @@ -11,6 +11,7 @@ using System; using System.Collections.Generic; +using System.Reflection; namespace CatLib { @@ -718,6 +719,32 @@ public static Func Factory(this IContainer container, params return () => (TService)container.Make(container.Type2Service(typeof(TService)), userParams); } + /// + /// 扩展容器中的服务 + /// 允许在服务构建的过程中配置或者替换服务 + /// 如果服务已经被构建,拓展会立即生效。 + /// + /// 服务名或别名 + /// 服务容器 + /// 闭包 + public static void Extend(this IContainer container, Func closure) + { + container.Extend(container.Type2Service(typeof(TService)), closure); + } + + /// + /// 扩展容器中的服务 + /// 允许在服务构建的过程中配置或者替换服务 + /// 如果服务已经被构建,拓展会立即生效。 + /// + /// 服务名或别名 + /// 服务容器 + /// 闭包 + public static void Extend(this IContainer container, Func closure) + { + container.Extend(container.Type2Service(typeof(TService)), (instance, _) => closure(instance)); + } + /// /// 当静态服务被释放时 /// @@ -730,6 +757,42 @@ public static IContainer OnRelease(this IContainer container, Action cal return container.OnRelease((_, instance) => callback(instance)); } + /// + /// 当静态服务被释放时 + /// + /// 服务容器 + /// 处理释放时的回调 + /// 当前容器实例 + public static IContainer OnRelease(this IContainer container, Action closure) + { + Guard.Requires(closure != null); + return container.OnRelease((_, instance) => + { + if (instance is T) + { + closure((T)instance); + } + }); + } + + /// + /// 当静态服务被释放时 + /// + /// 服务容器 + /// 处理释放时的回调 + /// 当前容器实例 + public static IContainer OnRelease(this IContainer container, Action closure) + { + Guard.Requires(closure != null); + return container.OnRelease((bindData, instance) => + { + if (instance is T) + { + closure(bindData, (T)instance); + } + }); + } + /// /// 当服务被解决时,生成的服务会经过注册的回调函数 /// @@ -742,7 +805,125 @@ public static IContainer OnResolving(this IContainer container, Action c return container.OnResolving((_, instance) => { callback(instance); - return instance; + }); + } + + /// + /// 当服务被解决时,生成的服务会经过注册的回调函数 + /// 只有类型和给定的类型相匹配才会被回调 + /// + /// 指定的类型 + /// 服务容器 + /// 闭包 + /// 当前容器对象 + public static IContainer OnResolving(this IContainer container, Action closure) + { + Guard.Requires(closure != null); + return container.OnResolving((_, instance) => + { + if (instance is T) + { + closure((T)instance); + } + }); + } + + /// + /// 当服务被解决时,生成的服务会经过注册的回调函数 + /// 只有类型和给定的类型相匹配才会被回调 + /// + /// 指定的类型 + /// 服务容器 + /// 闭包 + /// 当前容器对象 + public static IContainer OnResolving(this IContainer container, Action closure) + { + Guard.Requires(closure != null); + return container.OnResolving((bindData, instance) => + { + if (instance is T) + { + closure(bindData, (T) instance); + } + }); + } + + /// + /// 当服务被解决事件之后的回调 + /// + /// 服务容器 + /// 回调函数 + /// 当前容器对象 + public static IContainer OnAfterResolving(this IContainer container, Action callback) + { + Guard.Requires(callback != null); + return container.OnAfterResolving((_, instance) => + { + callback(instance); + }); + } + + /// + /// 当服务被解决事件之后的回调 + /// 只有类型和给定的类型相匹配才会被回调 + /// + /// 指定的类型 + /// 服务容器 + /// 闭包 + /// 当前容器对象 + public static IContainer OnAfterResolving(this IContainer container, Action closure) + { + Guard.Requires(closure != null); + return container.OnAfterResolving((_, instance) => + { + if (instance is T) + { + closure((T)instance); + } + }); + } + + /// + /// 当服务被解决事件之后的回调 + /// 只有类型和给定的类型相匹配才会被回调 + /// + /// 指定的类型 + /// 服务容器 + /// 闭包 + /// 当前容器对象 + public static IContainer OnAfterResolving(this IContainer container, Action closure) + { + Guard.Requires(closure != null); + return container.OnAfterResolving((bindData, instance) => + { + if (instance is T) + { + closure(bindData, (T)instance); + } + }); + } + + /// + /// 关注指定的服务,当服务触发重定义时调用指定对象的指定方法 + /// 调用是以依赖注入的形式进行的 + /// 服务的新建(第一次解决服务)操作并不会触发重定义 + /// + /// 服务容器 + /// 关注的服务名 + /// 当服务发生重定义时调用的目标 + /// 方法信息 + public static void Watch(this IContainer container, string service, object target, MethodInfo methodInfo) + { + Guard.Requires(methodInfo != null); + + if (!methodInfo.IsStatic) + { + Guard.Requires(target != null); + } + + container.OnRebound(service, (instance) => + { + container.Call(target, methodInfo, instance); }); } diff --git a/src/CatLib.Core/Support/Container/IBindData.cs b/src/CatLib.Core/Support/Container/IBindData.cs index acfd982..71af60a 100644 --- a/src/CatLib.Core/Support/Container/IBindData.cs +++ b/src/CatLib.Core/Support/Container/IBindData.cs @@ -52,15 +52,22 @@ public interface IBindData : IBindable /// /// 解决服务时触发的回调 /// - /// 解决事件 + /// 解决事件 /// 服务绑定数据 - IBindData OnResolving(Func func); + IBindData OnResolving(Action closure); + + /// + /// 解决服务时事件之后的回调 + /// + /// 解决事件 + /// 服务绑定数据 + IBindData OnAfterResolving(Action closure); /// /// 当服务被释放时 /// - /// 处理事件 + /// 处理事件 /// 服务绑定数据 - IBindData OnRelease(Action action); + IBindData OnRelease(Action closure); } } diff --git a/src/CatLib.Core/Support/Container/IContainer.cs b/src/CatLib.Core/Support/Container/IContainer.cs index 312f87c..e39d2de 100644 --- a/src/CatLib.Core/Support/Container/IContainer.cs +++ b/src/CatLib.Core/Support/Container/IContainer.cs @@ -162,7 +162,7 @@ public interface IContainer bool Release(string service); /// - /// 清空容器的所有实例,绑定,别名,标签,解决器,方法容器 + /// 清空容器的所有实例,绑定,别名,标签,解决器,方法容器, 扩展 /// void Flush(); @@ -196,7 +196,7 @@ public interface IContainer /// /// 服务名或者别名 /// 服务实例,如果构造失败那么返回null - object this[string service] { get; } + object this[string service] { get; set; } /// /// 获取一个回调,当执行回调可以生成指定的服务 @@ -214,18 +214,34 @@ public interface IContainer /// 当前容器对象 IContainer Alias(string alias, string service); + /// + /// 扩展容器中的服务 + /// 允许在服务构建的过程中配置或者替换服务 + /// 如果服务已经被构建,拓展会立即生效。 + /// + /// 服务名或别名 + /// 闭包 + void Extend(string service, Func closure); + /// /// 当服务被解决时触发的事件 /// - /// 回调函数 + /// 回调函数 /// 当前容器实例 - IContainer OnResolving(Func func); + IContainer OnResolving(Action closure); + + /// + /// 解决服务时事件之后的回调 + /// + /// 解决事件 + /// 服务绑定数据 + IContainer OnAfterResolving(Action closure); /// /// 当静态服务被释放时 /// - /// 处理释放时的回调 - IContainer OnRelease(Action action); + /// 处理释放时的回调 + IContainer OnRelease(Action closure); /// /// 当查找类型无法找到时会尝试去调用开发者提供的查找类型函数 @@ -236,23 +252,15 @@ public interface IContainer IContainer OnFindType(Func func, int priority = int.MaxValue); /// - /// 当一个已经被解决的服务,发生重定义时触发 + /// 关注指定的服务,当服务触发重定义时调用指定对象的指定方法 + /// 调用是以依赖注入的形式进行的 + /// 服务的新建(第一次解决服务)操作并不会触发重定义 /// /// 服务名 /// 回调 /// 服务容器 IContainer OnRebound(string service, Action callback); - /// - /// 关注指定的服务,当服务触发重定义时调用指定对象的指定方法 - /// 调用是以依赖注入的形式进行的 - /// 服务的新建(第一次解决服务)操作并不会触发重定义 - /// - /// 关注的服务名 - /// 当服务发生重定义时调用的目标 - /// 方法信息 - void Watch(string service, object target, MethodInfo methodInfo); - /// /// 在回调区间内暂时性的静态化服务实例 /// diff --git a/src/CatLib.Core/Support/Container/MethodContainer.cs b/src/CatLib.Core/Support/Container/MethodContainer.cs index 182b40d..93fe3bc 100644 --- a/src/CatLib.Core/Support/Container/MethodContainer.cs +++ b/src/CatLib.Core/Support/Container/MethodContainer.cs @@ -80,7 +80,7 @@ public IMethodBind Bind(string method, object target, MethodInfo methodInfo) { if (methodMappings.ContainsKey(method)) { - throw new RuntimeException($"Method [{method}] is already {nameof(Bind)}"); + throw new LogicException($"Method [{method}] is already {nameof(Bind)}"); } var methodBind = new MethodBind(this, container, method, target, methodInfo); @@ -223,9 +223,9 @@ public void Flush() /// 生成一个方法没有找到异常 /// /// - private RuntimeException MakeMethodNotFoundException(string method) + private LogicException MakeMethodNotFoundException(string method) { - return new RuntimeException($"Method [{method}] is not found."); + return new LogicException($"Method [{method}] is not found."); } } } diff --git a/src/CatLib.Core/Support/Exception/CodeStandardException.cs b/src/CatLib.Core/Support/Exception/CodeStandardException.cs index 5dd8719..5a4540d 100644 --- a/src/CatLib.Core/Support/Exception/CodeStandardException.cs +++ b/src/CatLib.Core/Support/Exception/CodeStandardException.cs @@ -17,7 +17,7 @@ namespace CatLib /// 代码规范异常,引发本异常一般由于不正确的使用框架 /// [ExcludeFromCodeCoverage] - public class CodeStandardException : RuntimeException + public class CodeStandardException : LogicException { /// /// 代码规范异常 diff --git a/src/CatLib.Core/Support/Exception/LogicException.cs b/src/CatLib.Core/Support/Exception/LogicException.cs new file mode 100644 index 0000000..b81fd7d --- /dev/null +++ b/src/CatLib.Core/Support/Exception/LogicException.cs @@ -0,0 +1,47 @@ +/* + * This file is part of the CatLib package. + * + * (c) Yu Bin + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + * Document: http://catlib.io/ + */ + +using System; + +namespace CatLib +{ + /// + /// 代码逻辑异常 + /// + [ExcludeFromCodeCoverage] + public class LogicException : RuntimeException + { + /// + /// 代码逻辑异常 + /// + public LogicException() + { + + } + + /// + /// 代码逻辑异常 + /// + /// 异常消息 + public LogicException(string message) : base(message) + { + } + + /// + /// 代码逻辑异常 + /// + /// 异常消息 + /// 内部异常 + public LogicException(string message, Exception innerException) : base(message, innerException) + { + } + } +} \ No newline at end of file diff --git a/src/CatLib.Core/Support/SortSet/SortSet.cs b/src/CatLib.Core/Support/SortSet/SortSet.cs index 15550fe..2576e4a 100644 --- a/src/CatLib.Core/Support/SortSet/SortSet.cs +++ b/src/CatLib.Core/Support/SortSet/SortSet.cs @@ -142,7 +142,7 @@ public TElement Current { return current.Element; } - throw new RuntimeException($"Can not get {nameof(current)} element"); + throw new LogicException($"Can not get {nameof(current)} element"); } } @@ -157,7 +157,7 @@ object IEnumerator.Current { return current.Element; } - throw new RuntimeException($"Can not get {nameof(current)} element"); + throw new LogicException($"Can not get {nameof(current)} element"); } } diff --git a/src/CatLib.Core/Support/Template/Managed.cs b/src/CatLib.Core/Support/Template/Managed.cs index b1da623..2fd9882 100644 --- a/src/CatLib.Core/Support/Template/Managed.cs +++ b/src/CatLib.Core/Support/Template/Managed.cs @@ -51,7 +51,7 @@ public void Extend(Func builder, string name = null) if (extendBuilder.ContainsKey(name)) { - throw new RuntimeException($"Extend [{name}]({GetType()}) is already exists."); + throw new LogicException($"Extend [{name}]({GetType()}) is already exists."); } extendBuilder.Add(name, builder); @@ -139,7 +139,7 @@ private Func GetExtend(string name) if (!extendBuilder.TryGetValue(name, out Func result)) { - throw new RuntimeException($"Can not find [{name}]({GetType()}) Extend."); + throw new LogicException($"Can not find [{name}]({GetType()}) Extend."); } return result; diff --git a/src/CatLib.Core/Support/Util/Extension/StreamExtension.cs b/src/CatLib.Core/Support/Util/Extension/StreamExtension.cs index 26d2cb3..25ed07a 100644 --- a/src/CatLib.Core/Support/Util/Extension/StreamExtension.cs +++ b/src/CatLib.Core/Support/Util/Extension/StreamExtension.cs @@ -68,7 +68,7 @@ public static string ToText(this Stream source, Encoding encoding = null, bool c { if (!source.CanRead) { - throw new RuntimeException($"Can not read stream, {nameof(source.CanRead)} == false"); + throw new LogicException($"Can not read stream, {nameof(source.CanRead)} == false"); } encoding = encoding ?? Util.Encoding; diff --git a/src/CatLib.Core/Support/Util/Version.cs b/src/CatLib.Core/Support/Util/Version.cs index 02ecaf0..5496177 100644 --- a/src/CatLib.Core/Support/Util/Version.cs +++ b/src/CatLib.Core/Support/Util/Version.cs @@ -223,7 +223,7 @@ private void GuardVersion(string version) { if (!VersionMatcher.IsMatch(version)) { - throw new RuntimeException($"{nameof(version)} is invalid : {version}"); + throw new LogicException($"{nameof(version)} is invalid : {version}"); } }