From 6f5ff5ef71677bbd436139c2fbf5a46837279400 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Thu, 30 Nov 2017 14:54:15 +0800 Subject: [PATCH 01/91] code optimization --- src/CatLib.Core.Tests/Support/VersionTests.cs | 21 +++++++---- .../Support/Template/ISingleManaged.cs | 12 +++++- .../Support/Template/SingleManaged.cs | 12 +++++- src/CatLib.Core/Support/Util/Arr.cs | 1 - src/CatLib.Core/Support/Util/Version.cs | 37 ++++++++++++++----- 5 files changed, 64 insertions(+), 19 deletions(-) diff --git a/src/CatLib.Core.Tests/Support/VersionTests.cs b/src/CatLib.Core.Tests/Support/VersionTests.cs index 883b4b7..e7bc5b6 100644 --- a/src/CatLib.Core.Tests/Support/VersionTests.cs +++ b/src/CatLib.Core.Tests/Support/VersionTests.cs @@ -109,31 +109,38 @@ public void ThrowErrorVersion() { ExceptionAssert.Throws(() => { - new Version("1.01.2-beta.10+29830"); + var v = new Version("1.01.2-beta.10+29830"); + v.Compare("1.0.0"); }); ExceptionAssert.Throws(() => { - new Version("1.1b.2-beta.10+29830"); + var v = new Version("1.1b.2-beta.10+29830"); + v.Compare("1.0.0"); }); ExceptionAssert.Throws(() => { - new Version("1.1.2/beta.10+29830"); + var v = new Version("1.1.2/beta.10+29830"); + v.Compare("1.0.0"); }); ExceptionAssert.Throws(() => { - new Version("1.1.2-00.10+29830"); + var v = new Version("1.1.2-00.10+29830"); + v.Compare("1.0.0"); }); ExceptionAssert.Throws(() => { - new Version("1.1.2-+29830"); + var v = new Version("1.1.2-+29830"); + v.Compare("1.0.0"); }); ExceptionAssert.Throws(() => { - new Version("1.1.2-0.+29830"); + var v = new Version("1.1.2-0.+29830"); + v.Compare("1.0.0"); }); ExceptionAssert.Throws(() => { - new Version("1.1..2-0.beta2+29830"); + var v = new Version("1.1..2-0.beta2+29830"); + v.Compare("1.0.0"); }); } } diff --git a/src/CatLib.Core/Support/Template/ISingleManaged.cs b/src/CatLib.Core/Support/Template/ISingleManaged.cs index 4b91ee1..e77f8cf 100644 --- a/src/CatLib.Core/Support/Template/ISingleManaged.cs +++ b/src/CatLib.Core/Support/Template/ISingleManaged.cs @@ -1,4 +1,14 @@ - +/* + * 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/ + */ + namespace CatLib { /// diff --git a/src/CatLib.Core/Support/Template/SingleManaged.cs b/src/CatLib.Core/Support/Template/SingleManaged.cs index de30c8e..2b5d9fd 100644 --- a/src/CatLib.Core/Support/Template/SingleManaged.cs +++ b/src/CatLib.Core/Support/Template/SingleManaged.cs @@ -1,4 +1,14 @@ - +/* + * 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.Collections.Generic; namespace CatLib diff --git a/src/CatLib.Core/Support/Util/Arr.cs b/src/CatLib.Core/Support/Util/Arr.cs index d070b77..5f36cdd 100644 --- a/src/CatLib.Core/Support/Util/Arr.cs +++ b/src/CatLib.Core/Support/Util/Arr.cs @@ -10,7 +10,6 @@ */ using System; -using System.Diagnostics; namespace CatLib { diff --git a/src/CatLib.Core/Support/Util/Version.cs b/src/CatLib.Core/Support/Util/Version.cs index aa7bd59..43481ad 100644 --- a/src/CatLib.Core/Support/Util/Version.cs +++ b/src/CatLib.Core/Support/Util/Version.cs @@ -17,13 +17,28 @@ namespace CatLib /// /// 版本(遵循semver) /// - public sealed class Version + public class Version { /// /// 版本匹配正则式 /// - private static readonly Regex versionMatcher = new Regex( - @"^(?((?![0])\d+?|[0]))\.(?((?![0])\d+?|[0]))\.(?((?![0])\d+?|[0]))(?:-(?!\.)(?([a-zA-Z]\w*?|(?![0])\d+?|[0])(\.([a-zA-Z]\w*?|(?![0])\d+?|[0]))*?))?(?:\+(?!\.)(?([a-zA-Z]\w*?|(?![0])\d+?|[0])(\.([a-zA-Z]\w*?|(?![0])\d+?|[0]))*?))?$"); + private static Regex versionMatcher; + + /// + /// 版本匹配正则式 + /// + private static Regex VersionMatcher + { + get + { + if (versionMatcher == null) + { + versionMatcher = new Regex( + @"^(?((?![0])\d+?|[0]))\.(?((?![0])\d+?|[0]))\.(?((?![0])\d+?|[0]))(?:-(?!\.)(?([a-zA-Z]\w*?|(?![0])\d+?|[0])(\.([a-zA-Z]\w*?|(?![0])\d+?|[0]))*?))?(?:\+(?!\.)(?([a-zA-Z]\w*?|(?![0])\d+?|[0])(\.([a-zA-Z]\w*?|(?![0])\d+?|[0]))*?))?$"); + } + return versionMatcher; + } + } /// /// 原始版本信息 @@ -38,7 +53,7 @@ public sealed class Version /// /// 版本信息 /// - private struct VersionData + private class VersionData { /// /// 主版本号 @@ -71,7 +86,7 @@ private struct VersionData /// public VersionData(string version) { - var match = versionMatcher.Match(version); + var match = VersionMatcher.Match(version); Major = int.Parse(match.Groups["major"].ToString()); Minor = int.Parse(match.Groups["minor"].ToString()); Revised = int.Parse(match.Groups["revised"].ToString()); @@ -86,7 +101,7 @@ public VersionData(string version) /// 主版本号 /// 次版本号 /// 修订版本号 - public Version(int major, int minor, int revised) + public Version(int major, int minor, int revised) : this(major + "." + minor + "." + revised) { } @@ -97,9 +112,7 @@ public Version(int major, int minor, int revised) /// 版本号 public Version(string version) { - GuardVersion(version); this.version = version; - current = new VersionData(version); } /// @@ -112,6 +125,12 @@ public Version(string version) /// 比较结果 public int Compare(string version) { + if (current == null) + { + GuardVersion(this.version); + current = new VersionData(this.version); + } + GuardVersion(version); var compared = new VersionData(version); @@ -213,7 +232,7 @@ private int CompareBlock(string left, string right) /// 输入版本 private void GuardVersion(string version) { - if (!versionMatcher.IsMatch(version)) + if (!VersionMatcher.IsMatch(version)) { throw new RuntimeException("version is invalid"); } From 49e907ad484a22e48417150a51303ce4c32d8e45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Thu, 30 Nov 2017 20:04:39 +0800 Subject: [PATCH 02/91] trigger bug fixed --- src/CatLib.Core/CatLib/App.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CatLib.Core/CatLib/App.cs b/src/CatLib.Core/CatLib/App.cs index f3371e5..d916bd9 100644 --- a/src/CatLib.Core/CatLib/App.cs +++ b/src/CatLib.Core/CatLib/App.cs @@ -158,7 +158,7 @@ public static void SetDebugLevel(DebugLevels level) /// 事件名称 /// 载荷 /// 事件结果 - public static object Trigger(string eventName, object payload = null) + public static object[] Trigger(string eventName, object payload = null) { return Handler.Trigger(eventName, payload); } From b180a5b67337bceffe51aca675236367ec310ed9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Fri, 1 Dec 2017 13:35:55 +0800 Subject: [PATCH 03/91] add method container --- .../Support/Container/MethodContainer.cs | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/CatLib.Core/Support/Container/MethodContainer.cs diff --git a/src/CatLib.Core/Support/Container/MethodContainer.cs b/src/CatLib.Core/Support/Container/MethodContainer.cs new file mode 100644 index 0000000..eb0ecc8 --- /dev/null +++ b/src/CatLib.Core/Support/Container/MethodContainer.cs @@ -0,0 +1,46 @@ +/* + * 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.Reflection; + +namespace CatLib.Core.Support.Container +{ + /// + /// 方法容器 + /// + internal sealed class MethodContainer + { + /// + /// 依赖注入容器 + /// + private IContainer container; + + /// + /// 构建一个新的方法容器 + /// + /// + internal MethodContainer(IContainer container) + { + this.container = container; + } + + /// + /// 绑定一个方法 + /// + /// 通过这个名字可以调用方法 + /// 被调用的方法 + /// + public int BindMethod(string name, MethodInfo method) + { + return 0; + } + } +} From bda4ee23e12c48119d38212a1183b163d4fb4cdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Fri, 1 Dec 2017 14:19:34 +0800 Subject: [PATCH 04/91] project update --- .../CatLib.Core.NetStandard.csproj | 6 +- .../Support/Container/BindService.cs | 286 ++++++++++++++++++ src/CatLib.Core/CatLib.Core.csproj | 5 +- .../Container/{Internal => }/IBindData.cs | 0 .../Container/{Internal => }/IGivenData.cs | 0 5 files changed, 292 insertions(+), 5 deletions(-) create mode 100644 src/CatLib.Core.NetStandard/Support/Container/BindService.cs rename src/CatLib.Core/Support/Container/{Internal => }/IBindData.cs (100%) rename src/CatLib.Core/Support/Container/{Internal => }/IGivenData.cs (100%) diff --git a/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj b/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj index 9c78109..bc4ce19 100644 --- a/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj +++ b/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj @@ -69,10 +69,11 @@ + + - - + @@ -113,7 +114,6 @@ - diff --git a/src/CatLib.Core.NetStandard/Support/Container/BindService.cs b/src/CatLib.Core.NetStandard/Support/Container/BindService.cs new file mode 100644 index 0000000..e38aca2 --- /dev/null +++ b/src/CatLib.Core.NetStandard/Support/Container/BindService.cs @@ -0,0 +1,286 @@ +/* + * 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; +using System.Collections.Generic; + +namespace CatLib +{ + /// + /// 服务绑定数据 + /// + internal sealed class BindService : IBindService + { + /// + /// 当前绑定服务的服务名 + /// + public string Service { get; private set; } + + /// + /// 服务实现,执行这个委托将会获得服务实例 + /// + public Func Concrete { get; private set; } + + /// + /// 当前绑定的服务是否是静态服务 + /// + public bool IsStatic { get; private set; } + + /// + /// 服务关系上下文 + /// 当前服务需求某个服务时可以指定给与什么服务 + /// + private Dictionary contextual; + + /// + /// 父级容器 + /// + private readonly Container container; + + /// + /// 服务构造修饰器 + /// + private List> resolving; + + /// + /// 服务构造修饰器 + /// + private List> release; + + /// + /// 是否被释放 + /// + private bool isDestroy; + + /// + /// 同步锁 + /// + private readonly object syncRoot = new object(); + + /// + /// 给与数据 + /// + private GivenData given; + + /// + /// 构建一个绑定数据 + /// + /// 服务父级容器 + /// 服务名 + /// 服务实现 + /// 服务是否是静态的 + internal BindService(Container container, string service, Func concrete, bool isStatic) + { + this.container = container; + Service = service; + Concrete = concrete; + IsStatic = isStatic; + isDestroy = false; + } + + /// + /// 当需求某个服务 + /// + /// 服务名 + /// 绑定关系临时数据 + public IGivenData Needs(string service) + { + Guard.NotEmptyOrNull(service, "service"); + lock (syncRoot) + { + GuardIsDestroy(); + if (given == null) + { + given = new GivenData(container, this); + } + given.Needs(service); + } + return given; + } + + /// + /// 当需求某个服务 + /// + /// 服务类型 + /// 绑定关系临时数据 + public IGivenData Needs() + { + return Needs(container.Type2Service(typeof(T))); + } + + /// + /// 为服务设定一个别名 + /// + /// 别名 + /// 服务绑定数据 + public IBindService Alias() + { + return Alias(container.Type2Service(typeof(T))); + } + + /// + /// 为服务设定一个别名 + /// + /// 别名 + /// 服务绑定数据 + public IBindService Alias(string alias) + { + lock (syncRoot) + { + GuardIsDestroy(); + Guard.NotEmptyOrNull(alias, "alias"); + container.Alias(alias, Service); + return this; + } + } + + /// + /// 解决服务时触发的回调 + /// + /// 解决事件 + /// 服务绑定数据 + public IBindService OnResolving(Func func) + { + Guard.NotNull(func, "func"); + lock (syncRoot) + { + GuardIsDestroy(); + if (resolving == null) + { + resolving = new List>(); + } + resolving.Add(func); + } + return this; + } + + /// + /// 当静态服务被释放时 + /// + /// 处理事件 + /// 服务绑定数据 + public IBindService OnRelease(Action action) + { + Guard.NotNull(action, "action"); + if (!IsStatic) + { + throw new RuntimeException("Service [" + Service + "] is not Singleton(Static) Bind , Can not call OnRelease()."); + } + lock (syncRoot) + { + GuardIsDestroy(); + if (release == null) + { + release = new List>(); + } + release.Add(action); + } + return this; + } + + /// + /// 移除绑定服务 , 在解除绑定时如果是静态化物体将会触发释放 + /// + public void UnBind() + { + lock (syncRoot) + { + isDestroy = true; + container.UnBind(Service); + } + } + + /// + /// 获取上下文的需求关系 + /// + /// 需求的服务 + /// 给与的服务 + internal string GetContextual(string needs) + { + if (contextual == null) + { + return needs; + } + + string contextualNeeds; + return contextual.TryGetValue(needs, out contextualNeeds) ? contextualNeeds : needs; + } + + /// + /// 执行服务修饰器 + /// + /// 服务实例 + /// 修饰后的服务实例 + internal object ExecResolvingDecorator(object obj) + { + if (resolving == null) + { + return obj; + } + foreach (var func in resolving) + { + obj = func.Invoke(this, obj); + } + return obj; + } + + /// + /// 执行服务释放处理器 + /// + /// 服务实例 + internal void ExecReleaseDecorator(object obj) + { + if (release == null) + { + return; + } + foreach (var action in release) + { + action.Invoke(this, obj); + } + } + + /// + /// 为服务增加上下文 + /// + /// 需求什么服务 + /// 给与什么服务 + /// 服务绑定数据 + internal BindService AddContextual(string needs, string given) + { + lock (syncRoot) + { + GuardIsDestroy(); + if (contextual == null) + { + contextual = new Dictionary(); + } + if (contextual.ContainsKey(needs)) + { + throw new RuntimeException("Needs [" + needs + "] is already exist."); + } + contextual.Add(needs, given); + return this; + } + } + + /// + /// 守卫是否被释放 + /// + private void GuardIsDestroy() + { + if (isDestroy) + { + throw new RuntimeException("Current Instance has be mark Destroy."); + } + } + } +} \ No newline at end of file diff --git a/src/CatLib.Core/CatLib.Core.csproj b/src/CatLib.Core/CatLib.Core.csproj index 86e3d2c..24c35ea 100644 --- a/src/CatLib.Core/CatLib.Core.csproj +++ b/src/CatLib.Core/CatLib.Core.csproj @@ -45,6 +45,7 @@ + @@ -58,8 +59,8 @@ - - + + diff --git a/src/CatLib.Core/Support/Container/Internal/IBindData.cs b/src/CatLib.Core/Support/Container/IBindData.cs similarity index 100% rename from src/CatLib.Core/Support/Container/Internal/IBindData.cs rename to src/CatLib.Core/Support/Container/IBindData.cs diff --git a/src/CatLib.Core/Support/Container/Internal/IGivenData.cs b/src/CatLib.Core/Support/Container/IGivenData.cs similarity index 100% rename from src/CatLib.Core/Support/Container/Internal/IGivenData.cs rename to src/CatLib.Core/Support/Container/IGivenData.cs From 2b4e9ca1109155edd426fd31527b7ff37e4bb5c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Fri, 1 Dec 2017 15:34:45 +0800 Subject: [PATCH 05/91] add bindable --- .../CatLib.Core.NetStandard.csproj | 2 + .../Support/Container/BindService.cs | 286 ------------------ .../Support/Container/GivenDataTests.cs | 6 +- src/CatLib.Core/CatLib.Core.csproj | 2 + src/CatLib.Core/Support/Container/BindData.cs | 136 +-------- src/CatLib.Core/Support/Container/Bindable.cs | 161 ++++++++++ .../Support/Container/Container.cs | 12 +- .../Support/Container/GivenData.cs | 24 +- .../Support/Container/IBindData.cs | 26 +- .../Support/Container/IBindable.cs | 44 +++ .../Support/Container/IGivenData.cs | 6 +- .../Support/Container/MethodContainer.cs | 13 +- 12 files changed, 249 insertions(+), 469 deletions(-) delete mode 100644 src/CatLib.Core.NetStandard/Support/Container/BindService.cs create mode 100644 src/CatLib.Core/Support/Container/Bindable.cs create mode 100644 src/CatLib.Core/Support/Container/IBindable.cs diff --git a/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj b/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj index bc4ce19..b90bdac 100644 --- a/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj +++ b/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj @@ -65,10 +65,12 @@ + + diff --git a/src/CatLib.Core.NetStandard/Support/Container/BindService.cs b/src/CatLib.Core.NetStandard/Support/Container/BindService.cs deleted file mode 100644 index e38aca2..0000000 --- a/src/CatLib.Core.NetStandard/Support/Container/BindService.cs +++ /dev/null @@ -1,286 +0,0 @@ -/* - * 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; -using System.Collections.Generic; - -namespace CatLib -{ - /// - /// 服务绑定数据 - /// - internal sealed class BindService : IBindService - { - /// - /// 当前绑定服务的服务名 - /// - public string Service { get; private set; } - - /// - /// 服务实现,执行这个委托将会获得服务实例 - /// - public Func Concrete { get; private set; } - - /// - /// 当前绑定的服务是否是静态服务 - /// - public bool IsStatic { get; private set; } - - /// - /// 服务关系上下文 - /// 当前服务需求某个服务时可以指定给与什么服务 - /// - private Dictionary contextual; - - /// - /// 父级容器 - /// - private readonly Container container; - - /// - /// 服务构造修饰器 - /// - private List> resolving; - - /// - /// 服务构造修饰器 - /// - private List> release; - - /// - /// 是否被释放 - /// - private bool isDestroy; - - /// - /// 同步锁 - /// - private readonly object syncRoot = new object(); - - /// - /// 给与数据 - /// - private GivenData given; - - /// - /// 构建一个绑定数据 - /// - /// 服务父级容器 - /// 服务名 - /// 服务实现 - /// 服务是否是静态的 - internal BindService(Container container, string service, Func concrete, bool isStatic) - { - this.container = container; - Service = service; - Concrete = concrete; - IsStatic = isStatic; - isDestroy = false; - } - - /// - /// 当需求某个服务 - /// - /// 服务名 - /// 绑定关系临时数据 - public IGivenData Needs(string service) - { - Guard.NotEmptyOrNull(service, "service"); - lock (syncRoot) - { - GuardIsDestroy(); - if (given == null) - { - given = new GivenData(container, this); - } - given.Needs(service); - } - return given; - } - - /// - /// 当需求某个服务 - /// - /// 服务类型 - /// 绑定关系临时数据 - public IGivenData Needs() - { - return Needs(container.Type2Service(typeof(T))); - } - - /// - /// 为服务设定一个别名 - /// - /// 别名 - /// 服务绑定数据 - public IBindService Alias() - { - return Alias(container.Type2Service(typeof(T))); - } - - /// - /// 为服务设定一个别名 - /// - /// 别名 - /// 服务绑定数据 - public IBindService Alias(string alias) - { - lock (syncRoot) - { - GuardIsDestroy(); - Guard.NotEmptyOrNull(alias, "alias"); - container.Alias(alias, Service); - return this; - } - } - - /// - /// 解决服务时触发的回调 - /// - /// 解决事件 - /// 服务绑定数据 - public IBindService OnResolving(Func func) - { - Guard.NotNull(func, "func"); - lock (syncRoot) - { - GuardIsDestroy(); - if (resolving == null) - { - resolving = new List>(); - } - resolving.Add(func); - } - return this; - } - - /// - /// 当静态服务被释放时 - /// - /// 处理事件 - /// 服务绑定数据 - public IBindService OnRelease(Action action) - { - Guard.NotNull(action, "action"); - if (!IsStatic) - { - throw new RuntimeException("Service [" + Service + "] is not Singleton(Static) Bind , Can not call OnRelease()."); - } - lock (syncRoot) - { - GuardIsDestroy(); - if (release == null) - { - release = new List>(); - } - release.Add(action); - } - return this; - } - - /// - /// 移除绑定服务 , 在解除绑定时如果是静态化物体将会触发释放 - /// - public void UnBind() - { - lock (syncRoot) - { - isDestroy = true; - container.UnBind(Service); - } - } - - /// - /// 获取上下文的需求关系 - /// - /// 需求的服务 - /// 给与的服务 - internal string GetContextual(string needs) - { - if (contextual == null) - { - return needs; - } - - string contextualNeeds; - return contextual.TryGetValue(needs, out contextualNeeds) ? contextualNeeds : needs; - } - - /// - /// 执行服务修饰器 - /// - /// 服务实例 - /// 修饰后的服务实例 - internal object ExecResolvingDecorator(object obj) - { - if (resolving == null) - { - return obj; - } - foreach (var func in resolving) - { - obj = func.Invoke(this, obj); - } - return obj; - } - - /// - /// 执行服务释放处理器 - /// - /// 服务实例 - internal void ExecReleaseDecorator(object obj) - { - if (release == null) - { - return; - } - foreach (var action in release) - { - action.Invoke(this, obj); - } - } - - /// - /// 为服务增加上下文 - /// - /// 需求什么服务 - /// 给与什么服务 - /// 服务绑定数据 - internal BindService AddContextual(string needs, string given) - { - lock (syncRoot) - { - GuardIsDestroy(); - if (contextual == null) - { - contextual = new Dictionary(); - } - if (contextual.ContainsKey(needs)) - { - throw new RuntimeException("Needs [" + needs + "] is already exist."); - } - contextual.Add(needs, given); - return this; - } - } - - /// - /// 守卫是否被释放 - /// - private void GuardIsDestroy() - { - if (isDestroy) - { - throw new RuntimeException("Current Instance has be mark Destroy."); - } - } - } -} \ No newline at end of file diff --git a/src/CatLib.Core.Tests/Support/Container/GivenDataTests.cs b/src/CatLib.Core.Tests/Support/Container/GivenDataTests.cs index d90fbe6..c279dea 100644 --- a/src/CatLib.Core.Tests/Support/Container/GivenDataTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/GivenDataTests.cs @@ -28,12 +28,12 @@ public void CanGiven() { var container = new Container(); var bindData = new BindData(container, "CanGiven", (app, param) => "hello world", false); - var givenData = new GivenData(container, bindData); + var givenData = new GivenData(container, bindData); givenData.Needs("needs1"); givenData.Given("hello"); Assert.AreEqual("hello", bindData.GetContextual("needs1")); - givenData = new GivenData(container, bindData); + givenData = new GivenData(container, bindData); givenData.Needs("needs2"); givenData.Given(); Assert.AreEqual(container.Type2Service(typeof(GivenDataTest)), bindData.GetContextual("needs2")); @@ -47,7 +47,7 @@ public void CheckGivenIllegalValue() { var container = new Container(); var bindData = new BindData(container, "CanGiven", (app, param) => "hello world", false); - var givenData = new GivenData(container, bindData); + var givenData = new GivenData(container, bindData); givenData.Needs("needs"); ExceptionAssert.Throws(() => diff --git a/src/CatLib.Core/CatLib.Core.csproj b/src/CatLib.Core/CatLib.Core.csproj index 24c35ea..baf9545 100644 --- a/src/CatLib.Core/CatLib.Core.csproj +++ b/src/CatLib.Core/CatLib.Core.csproj @@ -45,6 +45,8 @@ + + diff --git a/src/CatLib.Core/Support/Container/BindData.cs b/src/CatLib.Core/Support/Container/BindData.cs index 97f0a63..17bff79 100644 --- a/src/CatLib.Core/Support/Container/BindData.cs +++ b/src/CatLib.Core/Support/Container/BindData.cs @@ -17,13 +17,8 @@ namespace CatLib /// /// 服务绑定数据 /// - internal sealed class BindData : IBindData + internal sealed class BindData : Bindable, IBindData { - /// - /// 当前绑定服务的服务名 - /// - public string Service { get; private set; } - /// /// 服务实现,执行这个委托将会获得服务实例 /// @@ -34,17 +29,6 @@ internal sealed class BindData : IBindData /// public bool IsStatic { get; private set; } - /// - /// 服务关系上下文 - /// 当前服务需求某个服务时可以指定给与什么服务 - /// - private Dictionary contextual; - - /// - /// 父级容器 - /// - private readonly Container container; - /// /// 服务构造修饰器 /// @@ -55,21 +39,6 @@ internal sealed class BindData : IBindData /// private List> release; - /// - /// 是否被释放 - /// - private bool isDestroy; - - /// - /// 同步锁 - /// - private readonly object syncRoot = new object(); - - /// - /// 给与数据 - /// - private GivenData given; - /// /// 构建一个绑定数据 /// @@ -78,42 +47,10 @@ internal sealed class BindData : IBindData /// 服务实现 /// 服务是否是静态的 internal BindData(Container container, string service, Func concrete, bool isStatic) + :base(container, service) { - this.container = container; - Service = service; Concrete = concrete; IsStatic = isStatic; - isDestroy = false; - } - - /// - /// 当需求某个服务 - /// - /// 服务名 - /// 绑定关系临时数据 - public IGivenData Needs(string service) - { - Guard.NotEmptyOrNull(service, "service"); - lock (syncRoot) - { - GuardIsDestroy(); - if (given == null) - { - given = new GivenData(container, this); - } - given.Needs(service); - } - return given; - } - - /// - /// 当需求某个服务 - /// - /// 服务类型 - /// 绑定关系临时数据 - public IGivenData Needs() - { - return Needs(container.Type2Service(typeof(T))); } /// @@ -123,7 +60,7 @@ public IGivenData Needs() /// 服务绑定数据 public IBindData Alias() { - return Alias(container.Type2Service(typeof(T))); + return Alias(Container.Type2Service(typeof(T))); } /// @@ -133,11 +70,11 @@ public IBindData Alias() /// 服务绑定数据 public IBindData Alias(string alias) { - lock (syncRoot) + lock (SyncRoot) { GuardIsDestroy(); Guard.NotEmptyOrNull(alias, "alias"); - container.Alias(alias, Service); + Container.Alias(alias, Service); return this; } } @@ -150,7 +87,7 @@ public IBindData Alias(string alias) public IBindData OnResolving(Func func) { Guard.NotNull(func, "func"); - lock (syncRoot) + lock (SyncRoot) { GuardIsDestroy(); if (resolving == null) @@ -174,7 +111,7 @@ public IBindData OnRelease(Action action) { throw new RuntimeException("Service [" + Service + "] is not Singleton(Static) Bind , Can not call OnRelease()."); } - lock (syncRoot) + lock (SyncRoot) { GuardIsDestroy(); if (release == null) @@ -189,29 +126,9 @@ public IBindData OnRelease(Action action) /// /// 移除绑定服务 , 在解除绑定时如果是静态化物体将会触发释放 /// - public void UnBind() - { - lock (syncRoot) - { - isDestroy = true; - container.UnBind(Service); - } - } - - /// - /// 获取上下文的需求关系 - /// - /// 需求的服务 - /// 给与的服务 - internal string GetContextual(string needs) + protected override void ReleaseBind() { - if (contextual == null) - { - return needs; - } - - string contextualNeeds; - return contextual.TryGetValue(needs, out contextualNeeds) ? contextualNeeds : needs; + Container.UnBind(Service); } /// @@ -247,40 +164,5 @@ internal void ExecReleaseDecorator(object obj) action.Invoke(this, obj); } } - - /// - /// 为服务增加上下文 - /// - /// 需求什么服务 - /// 给与什么服务 - /// 服务绑定数据 - internal BindData AddContextual(string needs, string given) - { - lock (syncRoot) - { - GuardIsDestroy(); - if (contextual == null) - { - contextual = new Dictionary(); - } - if (contextual.ContainsKey(needs)) - { - throw new RuntimeException("Needs [" + needs + "] is already exist."); - } - contextual.Add(needs, given); - return this; - } - } - - /// - /// 守卫是否被释放 - /// - private void GuardIsDestroy() - { - if (isDestroy) - { - throw new RuntimeException("Current Instance has be mark Destroy."); - } - } } } \ No newline at end of file diff --git a/src/CatLib.Core/Support/Container/Bindable.cs b/src/CatLib.Core/Support/Container/Bindable.cs new file mode 100644 index 0000000..d17020b --- /dev/null +++ b/src/CatLib.Core/Support/Container/Bindable.cs @@ -0,0 +1,161 @@ +/* + * 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.Collections.Generic; + +namespace CatLib +{ + /// + /// 可绑定对象 + /// + internal abstract class Bindable : IBindable where TReturn : class, IBindable + { + /// + /// 当前绑定的名字 + /// + public string Service { get; private set; } + + /// + /// 服务关系上下文 + /// 当前服务需求某个服务时可以指定给与什么服务 + /// + private Dictionary contextual; + + /// + /// 给与数据 + /// + private GivenData given; + + /// + /// 是否被释放 + /// + private bool isDestroy; + + /// + /// 父级容器 + /// + protected readonly Container Container; + + /// + /// 同步锁 + /// + protected readonly object SyncRoot = new object(); + + /// + /// 构建一个绑定数据 + /// + /// 依赖注入容器 + /// 服务名 + internal Bindable(Container container, string service) + { + Container = container; + Service = service; + isDestroy = false; + } + + /// + /// 当需求某个服务 + /// + /// 服务名 + /// 绑定关系临时数据 + public IGivenData Needs(string service) + { + Guard.NotEmptyOrNull(service, "service"); + lock (SyncRoot) + { + GuardIsDestroy(); + if (given == null) + { + given = new GivenData(Container, this); + } + given.Needs(service); + } + return given; + } + + /// + /// 当需求某个服务 + /// + /// 服务类型 + /// 绑定关系临时数据 + public IGivenData Needs() + { + return Needs(Container.Type2Service(typeof(T))); + } + + /// + /// 为服务增加上下文 + /// + /// 需求什么服务 + /// 给与什么服务 + /// 服务绑定数据 + internal Bindable AddContextual(string needs, string given) + { + lock (SyncRoot) + { + GuardIsDestroy(); + if (contextual == null) + { + contextual = new Dictionary(); + } + if (contextual.ContainsKey(needs)) + { + throw new RuntimeException("Needs [" + needs + "] is already exist."); + } + contextual.Add(needs, given); + return this; + } + } + + /// + /// 获取上下文的需求关系 + /// + /// 需求的服务 + /// 给与的服务 + internal string GetContextual(string needs) + { + if (contextual == null) + { + return needs; + } + string contextualNeeds; + return contextual.TryGetValue(needs, out contextualNeeds) ? contextualNeeds : needs; + } + + /// + /// 解除绑定 + /// + public void UnBind() + { + lock (SyncRoot) + { + isDestroy = true; + ReleaseBind(); + } + } + + /// + /// 解除绑定 + /// + protected abstract void ReleaseBind(); + + /// + /// 守卫是否被释放 + /// + protected void GuardIsDestroy() + { + if (isDestroy) + { + throw new RuntimeException("Current Instance has be mark Destroy."); + } + } + } +} diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index e3db53c..b751104 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -761,7 +761,7 @@ private string Normalize(string service) /// 服务实例 /// 服务实例 /// 属性是必须的或者注入类型和需求类型不一致 - private void AttrInject(BindData makeServiceBindData, object makeServiceInstance) + private void AttrInject(Bindable makeServiceBindData, object makeServiceInstance) where T : class , IBindable { if (makeServiceInstance == null) { @@ -814,7 +814,7 @@ private void AttrInject(BindData makeServiceBindData, object makeServiceInstance /// 请求注入操作的服务绑定数据 /// 希望构造的服务名或者别名 /// 解决结果 - private object ResolveNonClassAttr(BindData makeServiceBindData, string service) + private object ResolveNonClassAttr(Bindable makeServiceBindData, string service) where T : class, IBindable { return Make(makeServiceBindData.GetContextual(service)); } @@ -825,7 +825,7 @@ private object ResolveNonClassAttr(BindData makeServiceBindData, string service) /// 请求注入操作的服务绑定数据 /// 希望构造的服务名或者别名 /// 解决结果 - private object ResloveClassAttr(BindData makeServiceBindData, string service) + private object ResloveClassAttr(Bindable makeServiceBindData, string service) where T : class, IBindable { return Make(makeServiceBindData.GetContextual(service)); } @@ -838,7 +838,7 @@ private object ResloveClassAttr(BindData makeServiceBindData, string service) /// 输入的构造参数列表 /// 服务所需参数的解决结果 /// 生成的实例类型和需求类型不一致 - private object[] GetDependencies(BindData makeServiceBindData, IList paramInfo, IList param) + private object[] GetDependencies(Bindable makeServiceBindData, IList paramInfo, IList param) where T : class, IBindable { var myParam = new List(); @@ -914,7 +914,7 @@ private object[] GetDependencies(BindData makeServiceBindData, IList请求注入操作的服务绑定数据 /// 希望解决的服务名或者别名 /// 解决结果 - private object ResolveNonClass(BindData makeServiceBindData, string service) + private object ResolveNonClass(Bindable makeServiceBindData, string service) where T : class, IBindable { return Make(makeServiceBindData.GetContextual(service)); } @@ -925,7 +925,7 @@ private object ResolveNonClass(BindData makeServiceBindData, string service) /// 请求注入操作的服务绑定数据 /// 希望解决的服务名或者别名 /// 解决结果 - private object ResloveClass(BindData makeServiceBindData, string service) + private object ResloveClass(Bindable makeServiceBindData, string service) where T : class, IBindable { return Make(makeServiceBindData.GetContextual(service)); } diff --git a/src/CatLib.Core/Support/Container/GivenData.cs b/src/CatLib.Core/Support/Container/GivenData.cs index af6fe37..90b671d 100644 --- a/src/CatLib.Core/Support/Container/GivenData.cs +++ b/src/CatLib.Core/Support/Container/GivenData.cs @@ -14,15 +14,15 @@ namespace CatLib /// /// 绑定关系临时数据,用于支持链式调用 /// - internal sealed class GivenData : IGivenData + internal sealed class GivenData : IGivenData where TReturn : class, IBindable { /// /// 绑定数据 /// - private readonly BindData bindData; - + private readonly Bindable bindable; + /// - /// 服务容器 + /// 父级容器 /// private readonly Container container; @@ -34,12 +34,12 @@ internal sealed class GivenData : IGivenData /// /// 绑定关系临时数据 /// - /// 服务容器 - /// 服务绑定数据 - internal GivenData(Container container, BindData bindData) + /// 依赖注入容器 + /// 可绑定数据 + internal GivenData(Container container, Bindable bindable) { - this.bindData = bindData; this.container = container; + this.bindable = bindable; } /// @@ -47,7 +47,7 @@ internal GivenData(Container container, BindData bindData) /// /// 需求什么服务 /// 绑定关系实例 - internal IGivenData Needs(string needs) + internal IGivenData Needs(string needs) { this.needs = needs; return this; @@ -58,10 +58,10 @@ internal IGivenData Needs(string needs) /// /// 给与的服务名或别名 /// 服务绑定数据 - public IBindData Given(string service) + public TReturn Given(string service) { Guard.NotEmptyOrNull(service , "service"); - return bindData.AddContextual(needs, service); + return bindable.AddContextual(needs, service) as TReturn; } /// @@ -69,7 +69,7 @@ public IBindData Given(string service) /// /// 给与的服务名或别名 /// 服务绑定数据 - public IBindData Given() + public TReturn Given() { return Given(container.Type2Service(typeof(T))); } diff --git a/src/CatLib.Core/Support/Container/IBindData.cs b/src/CatLib.Core/Support/Container/IBindData.cs index 5ee8608..46aac60 100644 --- a/src/CatLib.Core/Support/Container/IBindData.cs +++ b/src/CatLib.Core/Support/Container/IBindData.cs @@ -16,13 +16,8 @@ namespace CatLib /// /// 服务绑定数据 /// - public interface IBindData + public interface IBindData : IBindable { - /// - /// 服务名 - /// - string Service { get; } - /// /// 服务实现 /// @@ -33,20 +28,6 @@ public interface IBindData /// bool IsStatic { get; } - /// - /// 当需求某个服务 - /// - /// 服务名 - /// 绑定关系临时数据 - IGivenData Needs(string service); - - /// - /// 当需求某个服务 - /// - /// 服务类型 - /// 绑定关系临时数据 - IGivenData Needs(); - /// /// 为服务设定一个别名 /// @@ -74,10 +55,5 @@ public interface IBindData /// 处理事件 /// 服务绑定数据 IBindData OnRelease(Action action); - - /// - /// 移除绑定服务 , 在解除绑定时如果是静态化物体将会触发释放 - /// - void UnBind(); } } diff --git a/src/CatLib.Core/Support/Container/IBindable.cs b/src/CatLib.Core/Support/Container/IBindable.cs new file mode 100644 index 0000000..1b3102f --- /dev/null +++ b/src/CatLib.Core/Support/Container/IBindable.cs @@ -0,0 +1,44 @@ +/* + * 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/ + */ + +namespace CatLib +{ + /// + /// 被绑定对象 + /// + public interface IBindable + { + /// + /// 当前绑定的名字 + /// + string Service { get; } + + /// + /// 移除绑定 + /// 如果进行的是服务绑定 , 那么在解除绑定时如果是静态化物体将会触发释放 + /// + void UnBind(); + + /// + /// 当需求某个服务 + /// + /// 服务名 + /// 绑定关系临时数据 + IGivenData Needs(string service); + + /// + /// 当需求某个服务 + /// + /// 服务类型 + /// 绑定关系临时数据 + IGivenData Needs(); + } +} diff --git a/src/CatLib.Core/Support/Container/IGivenData.cs b/src/CatLib.Core/Support/Container/IGivenData.cs index 5a32824..ecf6f2f 100644 --- a/src/CatLib.Core/Support/Container/IGivenData.cs +++ b/src/CatLib.Core/Support/Container/IGivenData.cs @@ -14,20 +14,20 @@ namespace CatLib /// /// 绑定关系临时数据,用于支持链式调用 /// - public interface IGivenData + public interface IGivenData { /// /// 给与什么服务 /// /// 给与的服务名或别名 /// 服务绑定数据 - IBindData Given(string service); + TReturn Given(string service); /// /// 给与什么服务 /// /// 给与的服务名或别名 /// 服务绑定数据 - IBindData Given(); + TReturn Given(); } } \ No newline at end of file diff --git a/src/CatLib.Core/Support/Container/MethodContainer.cs b/src/CatLib.Core/Support/Container/MethodContainer.cs index eb0ecc8..7e3b3b8 100644 --- a/src/CatLib.Core/Support/Container/MethodContainer.cs +++ b/src/CatLib.Core/Support/Container/MethodContainer.cs @@ -9,9 +9,7 @@ * Document: http://catlib.io/ */ -using System.Reflection; - -namespace CatLib.Core.Support.Container +namespace CatLib { /// /// 方法容器 @@ -35,12 +33,13 @@ internal MethodContainer(IContainer container) /// /// 绑定一个方法 /// - /// 通过这个名字可以调用方法 - /// 被调用的方法 + /// 通过这个名字可以调用方法 + /// 方法调用目标 + /// 在方法调用目标中被调用的方法 /// - public int BindMethod(string name, MethodInfo method) + public int BindMethod(string method, object target, string call) { return 0; - } + } } } From 73c7d625f0bee5e31fbc07e916c3bc568a1fae23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Fri, 1 Dec 2017 17:26:43 +0800 Subject: [PATCH 06/91] add delegate call --- .../CatLib.Core.NetStandard.csproj | 2 + .../Support/Container/ContainerTests.cs | 16 +++++ src/CatLib.Core/CatLib.Core.csproj | 2 + src/CatLib.Core/Support/Container/Bindable.cs | 2 +- .../Support/Container/Container.cs | 71 +++++++++++++++++++ .../Support/Container/IMethodBindData.cs | 20 ++++++ .../Support/Container/MethodBindData.cs | 37 ++++++++++ .../Support/Container/MethodContainer.cs | 8 +-- 8 files changed, 153 insertions(+), 5 deletions(-) create mode 100644 src/CatLib.Core/Support/Container/IMethodBindData.cs create mode 100644 src/CatLib.Core/Support/Container/MethodBindData.cs diff --git a/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj b/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj index b90bdac..923b5a2 100644 --- a/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj +++ b/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj @@ -74,7 +74,9 @@ + + diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs index 1fc373d..34254f0 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs @@ -441,6 +441,22 @@ public void CheckLoopDependency() }); } + /// + /// 调用方法注入测试 + /// + [TestMethod] + public void CheckDelegateCall() + { + var container = MakeContainer(); + container.Instance(container); + + container.Call((Container cls, int n) => + { + Console.WriteLine(cls); + Assert.AreNotEqual(null, cls); + }); + } + /// /// 可以调用方法 /// diff --git a/src/CatLib.Core/CatLib.Core.csproj b/src/CatLib.Core/CatLib.Core.csproj index baf9545..cf1f071 100644 --- a/src/CatLib.Core/CatLib.Core.csproj +++ b/src/CatLib.Core/CatLib.Core.csproj @@ -47,6 +47,8 @@ + + diff --git a/src/CatLib.Core/Support/Container/Bindable.cs b/src/CatLib.Core/Support/Container/Bindable.cs index d17020b..955365b 100644 --- a/src/CatLib.Core/Support/Container/Bindable.cs +++ b/src/CatLib.Core/Support/Container/Bindable.cs @@ -54,7 +54,7 @@ internal abstract class Bindable : IBindable where TReturn : c /// /// 依赖注入容器 /// 服务名 - internal Bindable(Container container, string service) + protected Bindable(Container container, string service) { Container = container; Service = service; diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index b751104..678fb27 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -61,6 +61,11 @@ public class Container : IContainer /// private readonly SortSet, int> findType; + /// + /// 方法容器 + /// + private readonly MethodContainer methodContainer; + /// /// 同步锁 /// @@ -91,6 +96,7 @@ public Container() findType = new SortSet, int>(); injectTarget = typeof(InjectAttribute); buildStack = new Stack(); + methodContainer = new MethodContainer(this); } /// @@ -320,6 +326,21 @@ public IBindData Bind(string service, Func concret } } + /// + /// 绑定一个方法 + /// + /// + /// 通过这个名字可以调用方法 + /// 这个名字可以重复 + /// + /// 方法调用目标 + /// 在方法调用目标中被调用的方法 + /// 方法绑定数据 + public IMethodBindData BindMethod(string method, object target, string call) + { + return methodContainer.BindMethod(method, target, call); + } + /// /// 以依赖注入形式调用一个方法 /// @@ -361,6 +382,46 @@ public object Call(object instance, MethodInfo methodInfo, params object[] param } } + /// + /// 以依赖注入的形式调用一个方法 + /// + /// 方法 + public void Call(Action method) + { + Guard.Requires(method != null); + Call(method.Target, method.Method); + } + + /// + /// 以依赖注入的形式调用一个方法 + /// + /// 方法 + public void Call(Action method) + { + Guard.Requires(method != null); + Call(method.Target, method.Method); + } + + /// + /// 以依赖注入的形式调用一个方法 + /// + /// 方法 + public void Call(Action method) + { + Guard.Requires(method != null); + Call(method.Target, method.Method); + } + + /// + /// 以依赖注入的形式调用一个方法 + /// + /// 方法 + public void Call(Action method) + { + Guard.Requires(method != null); + Call(method.Target, method.Method); + } + /// /// 构造服务 /// @@ -423,6 +484,16 @@ public object this[string service] get { return Make(service); } } + /// + /// 获取一个回调,当执行回调可以生成指定的服务 + /// + /// 服务名或别名 + /// 回调方案 + public Func Factory(string service) + { + return () => Make(service); + } + /// /// 静态化一个服务,实例值会经过解决修饰器 /// diff --git a/src/CatLib.Core/Support/Container/IMethodBindData.cs b/src/CatLib.Core/Support/Container/IMethodBindData.cs new file mode 100644 index 0000000..3bca075 --- /dev/null +++ b/src/CatLib.Core/Support/Container/IMethodBindData.cs @@ -0,0 +1,20 @@ +/* + * 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/ + */ + +namespace CatLib +{ + /// + /// 方法绑定数据 + /// + public interface IMethodBindData : IBindable + { + } +} diff --git a/src/CatLib.Core/Support/Container/MethodBindData.cs b/src/CatLib.Core/Support/Container/MethodBindData.cs new file mode 100644 index 0000000..e31a154 --- /dev/null +++ b/src/CatLib.Core/Support/Container/MethodBindData.cs @@ -0,0 +1,37 @@ +/* + * 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/ + */ + +namespace CatLib +{ + /// + /// 方法绑定数据 + /// + internal sealed class MethodBindData : Bindable , IMethodBindData + { + /// + /// 构建一个绑定数据 + /// + /// 依赖注入容器 + /// 服务名 + public MethodBindData(Container container, string service) + :base(container, service) + { + } + + /// + /// 解除绑定 + /// + protected override void ReleaseBind() + { + + } + } +} diff --git a/src/CatLib.Core/Support/Container/MethodContainer.cs b/src/CatLib.Core/Support/Container/MethodContainer.cs index 7e3b3b8..109480e 100644 --- a/src/CatLib.Core/Support/Container/MethodContainer.cs +++ b/src/CatLib.Core/Support/Container/MethodContainer.cs @@ -19,13 +19,13 @@ internal sealed class MethodContainer /// /// 依赖注入容器 /// - private IContainer container; + private Container container; /// /// 构建一个新的方法容器 /// /// - internal MethodContainer(IContainer container) + internal MethodContainer(Container container) { this.container = container; } @@ -37,9 +37,9 @@ internal MethodContainer(IContainer container) /// 方法调用目标 /// 在方法调用目标中被调用的方法 /// - public int BindMethod(string method, object target, string call) + public IMethodBindData BindMethod(string method, object target, string call) { - return 0; + return null; } } } From 792f90499d22ad44e9f1bb6fb8802b63b058a341 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Fri, 1 Dec 2017 17:44:17 +0800 Subject: [PATCH 07/91] add wrap function --- .../Support/Container/Container.cs | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 678fb27..13a6649 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -422,6 +422,74 @@ public void Call(Action method) Call(method.Target, method.Method); } + /// + /// 包装一个依赖注入形式调用的一个方法 + /// + /// 方法 + /// 方法参数 + /// 包装方法 + public Action Wrap(Action method, params object[] param) + { + return () => + { + if (method != null) + { + Call(method.Target, method.Method, param); + } + }; + } + + /// + /// 包装一个依赖注入形式调用的一个方法 + /// + /// 方法 + /// 方法参数 + /// 包装方法 + public Action Wrap(Action method, params object[] param) + { + return () => + { + if (method != null) + { + Call(method.Target, method.Method, param); + } + }; + } + + /// + /// 包装一个依赖注入形式调用的一个方法 + /// + /// 方法 + /// 方法参数 + /// 包装方法 + public Action Wrap(Action method, params object[] param) + { + return () => + { + if (method != null) + { + Call(method.Target, method.Method, param); + } + }; + } + + /// + /// 包装一个依赖注入形式调用的一个方法 + /// + /// 方法 + /// 方法参数 + /// 包装方法 + public Action Wrap(Action method, params object[] param) + { + return () => + { + if (method != null) + { + Call(method.Target, method.Method, param); + } + }; + } + /// /// 构造服务 /// From 919364b46e16179c4daec676149d714f7574978d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Fri, 1 Dec 2017 18:26:48 +0800 Subject: [PATCH 08/91] interface update --- .../Support/Container/Container.cs | 14 +++- .../Support/Container/IContainer.cs | 70 +++++++++++++++++++ 2 files changed, 82 insertions(+), 2 deletions(-) diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 13a6649..e27e41e 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -196,6 +196,16 @@ public bool IsStatic(string service) return bind != null && bind.IsStatic; } + /// + /// 是否是别名 + /// + /// 名字 + /// 是否是别名 + public bool IsAlias(string name) + { + return aliases.ContainsKey(name); + } + /// /// 为服务设定一个别名 /// @@ -330,8 +340,8 @@ public IBindData Bind(string service, Func concret /// 绑定一个方法 /// /// - /// 通过这个名字可以调用方法 - /// 这个名字可以重复 + /// 方法名(可以被用于调用) + /// 名字可以重复,如果存在多个重复名字那么调用时同名的绑定的方法都将会被调用 /// /// 方法调用目标 /// 在方法调用目标中被调用的方法 diff --git a/src/CatLib.Core/Support/Container/IContainer.cs b/src/CatLib.Core/Support/Container/IContainer.cs index ffb55d4..0952d76 100644 --- a/src/CatLib.Core/Support/Container/IContainer.cs +++ b/src/CatLib.Core/Support/Container/IContainer.cs @@ -40,6 +40,13 @@ public interface IContainer /// 是否是静态化的 bool IsStatic(string service); + /// + /// 是否是别名 + /// + /// 名字 + /// 是否是别名 + bool IsAlias(string name); + /// /// 绑定一个服务 /// @@ -132,6 +139,62 @@ public interface IContainer /// 方法返回值 object Call(object instance, MethodInfo methodInfo, params object[] param); + /// + /// 以依赖注入的形式调用一个方法 + /// + /// 方法 + void Call(Action method); + + /// + /// 以依赖注入的形式调用一个方法 + /// + /// 方法 + void Call(Action method); + + /// + /// 以依赖注入的形式调用一个方法 + /// + /// 方法 + void Call(Action method); + + /// + /// 以依赖注入的形式调用一个方法 + /// + /// 方法 + void Call(Action method); + + /// + /// 包装一个依赖注入形式调用的一个方法 + /// + /// 方法 + /// 方法参数 + /// 包装方法 + Action Wrap(Action method, params object[] param); + + /// + /// 包装一个依赖注入形式调用的一个方法 + /// + /// 方法 + /// 方法参数 + /// 包装方法 + Action Wrap(Action method, params object[] param); + + /// + /// 包装一个依赖注入形式调用的一个方法 + /// + /// 方法 + /// 方法参数 + /// 包装方法 + Action Wrap(Action method, params object[] param); + + /// + /// 包装一个依赖注入形式调用的一个方法 + /// + /// 方法 + /// 方法参数 + /// 包装方法 + Action Wrap(Action method, params object[] param); + /// /// 构造服务,允许传入参数来决定构造函数的值 /// @@ -154,6 +217,13 @@ public interface IContainer /// 服务实例,如果构造失败那么返回null object this[string service] { get; } + /// + /// 获取一个回调,当执行回调可以生成指定的服务 + /// + /// 服务名或别名 + /// 回调方案 + Func Factory(string service); + /// /// 为服务设定一个别名 /// From e9e83958afc8c798d34885594008c3b6fc13ecc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Sat, 2 Dec 2017 10:57:54 +0800 Subject: [PATCH 09/91] add unit test --- .../Support/Container/ContainerTests.cs | 97 ++++++++++++++++++- .../Support/Util/ArrTests.cs | 13 ++- .../Support/Container/Container.cs | 15 --- .../Support/Container/ContainerExtend.cs | 41 +++++++- 4 files changed, 145 insertions(+), 21 deletions(-) diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs index 34254f0..4c03f9b 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs @@ -450,11 +450,104 @@ public void CheckDelegateCall() var container = MakeContainer(); container.Instance(container); - container.Call((Container cls, int n) => + container.Call((Container cls) => { - Console.WriteLine(cls); Assert.AreNotEqual(null, cls); }); + + container.Call((Container cls1, Container cls2) => + { + Assert.AreNotEqual(null, cls1); + Assert.AreNotEqual(null, cls2); + }); + + container.Call((Container cls1, Container cls2, Container cls3) => + { + Assert.AreNotEqual(null, cls1); + Assert.AreNotEqual(null, cls2); + Assert.AreNotEqual(null, cls3); + }); + + container.Call((Container cls1, Container cls2, Container cls3, Container cls4) => + { + Assert.AreNotEqual(null, cls1); + Assert.AreNotEqual(null, cls2); + Assert.AreNotEqual(null, cls3); + Assert.AreNotEqual(null, cls4); + + Assert.AreSame(cls1, cls4); + }); + } + + [TestMethod] + public void CheckWrapCall() + { + var container = MakeContainer(); + container.Instance(container); + + var callCount = 0; + var wrap = container.Wrap((Container cls) => + { + Assert.AreNotEqual(null, cls); + callCount++; + }); + wrap.Invoke(); + + wrap = container.Wrap((Container cls1, Container cls2) => + { + Assert.AreNotEqual(null, cls1); + Assert.AreNotEqual(null, cls2); + callCount++; + }); + wrap.Invoke(); + + wrap = container.Wrap((Container cls1, Container cls2, Container cls3) => + { + Assert.AreNotEqual(null, cls1); + Assert.AreNotEqual(null, cls2); + Assert.AreNotEqual(null, cls3); + callCount++; + }); + wrap.Invoke(); + + wrap = container.Wrap((Container cls1, Container cls2, Container cls3, Container cls4) => + { + Assert.AreNotEqual(null, cls1); + Assert.AreNotEqual(null, cls2); + Assert.AreNotEqual(null, cls3); + Assert.AreNotEqual(null, cls4); + + Assert.AreSame(cls1, cls4); + callCount++; + }); + wrap.Invoke(); + + Assert.AreEqual(4, callCount); + } + + [TestMethod] + public void TestFactory() + { + var container = MakeContainer(); + container.Instance(container); + container.Instance("hello", 123); + + var fac = container.Factory(); + Assert.AreEqual(container.Make(), fac.Invoke()); + + var fac2 = container.Factory("hello"); + Assert.AreEqual(123, fac2.Invoke()); + } + + [TestMethod] + public void TestIsAlias() + { + var container = MakeContainer(); + container.Instance(container); + container.Alias("123"); + + Assert.AreEqual(true, container.IsAlias("123")); + Assert.AreEqual(false, container.IsAlias(container.Type2Service(typeof(Container)))); } /// diff --git a/src/CatLib.Core.Tests/Support/Util/ArrTests.cs b/src/CatLib.Core.Tests/Support/Util/ArrTests.cs index 2c65e5e..345c228 100644 --- a/src/CatLib.Core.Tests/Support/Util/ArrTests.cs +++ b/src/CatLib.Core.Tests/Support/Util/ArrTests.cs @@ -520,6 +520,17 @@ public void TestDifference() Assert.AreEqual("c", result[2]); } - + [TestMethod] + public void TestDifferenceEmptyMatch() + { + var data = new[] { "a", "b", "c", "d", "e" }; + var result = Arr.Difference(data, null); + Assert.AreEqual(5, result.Length); + Assert.AreEqual("a", result[0]); + Assert.AreEqual("b", result[1]); + Assert.AreEqual("c", result[2]); + Assert.AreEqual("d", result[3]); + Assert.AreEqual("e", result[4]); + } } } diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index e27e41e..7344d1d 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -336,21 +336,6 @@ public IBindData Bind(string service, Func concret } } - /// - /// 绑定一个方法 - /// - /// - /// 方法名(可以被用于调用) - /// 名字可以重复,如果存在多个重复名字那么调用时同名的绑定的方法都将会被调用 - /// - /// 方法调用目标 - /// 在方法调用目标中被调用的方法 - /// 方法绑定数据 - public IMethodBindData BindMethod(string method, object target, string call) - { - return methodContainer.BindMethod(method, target, call); - } - /// /// 以依赖注入形式调用一个方法 /// diff --git a/src/CatLib.Core/Support/Container/ContainerExtend.cs b/src/CatLib.Core/Support/Container/ContainerExtend.cs index 90cce62..394e348 100644 --- a/src/CatLib.Core/Support/Container/ContainerExtend.cs +++ b/src/CatLib.Core/Support/Container/ContainerExtend.cs @@ -118,6 +118,18 @@ public static IBindData Bind(this IContainer container, string service, return container.Bind(service, concrete, false); } + /// + /// 为服务设定一个别名 + /// + /// 服务名 + /// 服务容器 + /// 别名 + /// 服务容器 + public static IContainer Alias(this IContainer container, string alias) + { + return container.Alias(alias, container.Type2Service(typeof(TService))); + } + /// /// 构造一个服务,允许传入构造参数 /// @@ -146,19 +158,42 @@ public static TService Make(this IContainer container) /// /// 服务实例转换到的类型 /// 服务容器 - /// 服务名 + /// 服务名或者别名 /// 服务实例 public static TConvert Make(this IContainer container, string service) { return (TConvert) container.Make(service); } + /// + /// 获取一个回调,当执行回调可以生成指定的服务 + /// + /// 服务名 + /// 服务容器 + /// 回调方案 + public static Func Factory(this IContainer container) + { + return () => (TService)container.Factory(container.Type2Service(typeof(TService))).Invoke(); + } + + /// + /// 获取一个回调,当执行回调可以生成指定的服务 + /// + /// 服务名 + /// 服务容器 + /// 服务名或者别名 + /// 回调方案 + public static Func Factory(this IContainer container, string service) + { + return () => (TService)container.Factory(service).Invoke(); + } + /// /// 释放服务 /// /// 服务名 /// 服务容器 - public static void Release(this IContainer container) where TService : class + public static void Release(this IContainer container) { container.Release(container.Type2Service(typeof(TService))); } @@ -169,7 +204,7 @@ public static void Release(this IContainer container) where TService : /// 服务名 /// 服务容器 /// 实例值 - public static void Instance(this IContainer container, object instance) where TService : class + public static void Instance(this IContainer container, object instance) { container.Instance(container.Type2Service(typeof(TService)), instance); } From ef3de0684be4db200d0be4bce43e1d59bbba2d05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Sat, 2 Dec 2017 12:52:08 +0800 Subject: [PATCH 10/91] container inject optimization --- .../Support/Container/ContainerTests.cs | 31 +----- .../Support/Util/ArrTests.cs | 82 +++++++++++++++ .../Support/Container/Container.cs | 99 ++++++++++++------- .../Support/Dispatcher/Dispatcher.cs | 8 +- src/CatLib.Core/Support/Util/Arr.cs | 16 +++ 5 files changed, 173 insertions(+), 63 deletions(-) diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs index 4c03f9b..d4769a5 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs @@ -620,11 +620,7 @@ public void CheckIllegalCallMethodParam() container.Bind(); var cls = new CallTestClass(); - ExceptionAssert.Throws(() => - { - container.Call(cls, "GetNumber", "illegal param"); - }); - + Assert.AreEqual(2, container.Call(cls, "GetNumber", "illegal param")); var result = container.Call(cls, "GetNumber", null); Assert.AreEqual(2, result); } @@ -1417,35 +1413,14 @@ public void TestBaseStructChange() public void TestBaseStructChangeInvalid() { var container = new Container(); - - var isThrow = false; - try - { - container.Call(this, "TestContainerCall", "100000000000000000000"); - } - catch (RuntimeException) - { - isThrow = true; - } - - Assert.AreEqual(true, isThrow); + Assert.AreEqual(0, container.Call(this, "TestContainerCall", "100000000000000000000")); } [TestMethod] public void TestFormatException() { var container = new Container(); - - var isThrow = false; - try - { - container.Call(this, "TestContainerCall", new ContainerTest()); - } - catch (RuntimeException) - { - isThrow = true; - } - Assert.AreEqual(true, isThrow); + Assert.AreEqual(0, container.Call(this, "TestContainerCall", new ContainerTest())); } internal class TestNoConstructorAccessClass diff --git a/src/CatLib.Core.Tests/Support/Util/ArrTests.cs b/src/CatLib.Core.Tests/Support/Util/ArrTests.cs index 345c228..8c4b493 100644 --- a/src/CatLib.Core.Tests/Support/Util/ArrTests.cs +++ b/src/CatLib.Core.Tests/Support/Util/ArrTests.cs @@ -532,5 +532,87 @@ public void TestDifferenceEmptyMatch() Assert.AreEqual("d", result[3]); Assert.AreEqual("e", result[4]); } + + [TestMethod] + public void TestRemoveAt() + { + var data = new[] { "a", "b", "c", "d", "e" }; + var result = Arr.RemoveAt(ref data, 1); + Assert.AreEqual("b", result); + Assert.AreEqual("a", data[0]); + Assert.AreEqual("c", data[1]); + Assert.AreEqual("d", data[2]); + Assert.AreEqual("e", data[3]); + Assert.AreEqual(4, data.Length); + + result = Arr.RemoveAt(ref data, 3); + Assert.AreEqual("e", result); + Assert.AreEqual("a", data[0]); + Assert.AreEqual("c", data[1]); + Assert.AreEqual("d", data[2]); + Assert.AreEqual(3, data.Length); + + result = Arr.RemoveAt(ref data, 0); + Assert.AreEqual("a", result); + Assert.AreEqual("c", data[0]); + Assert.AreEqual("d", data[1]); + Assert.AreEqual(2, data.Length); + + bool ex = false; + try + { + result = Arr.RemoveAt(ref data, 2); + } + catch (Exception) + { + ex = true; + } + Assert.AreEqual(true, ex); + + result = Arr.RemoveAt(ref data, 0); + Assert.AreEqual("c", result); + Assert.AreEqual("d", data[0]); + Assert.AreEqual(1, data.Length); + } + + [TestMethod] + public void TestRemoveAtNegativeNumber() + { + var data = new[] { "a", "b", "c", "d", "e" }; + var result = Arr.RemoveAt(ref data, -2); + Assert.AreEqual("d", result); + Assert.AreEqual("a", data[0]); + Assert.AreEqual("b", data[1]); + Assert.AreEqual("c", data[2]); + Assert.AreEqual("e", data[3]); + Assert.AreEqual(4, data.Length); + + result = Arr.RemoveAt(ref data, -1); + Assert.AreEqual("e", result); + Assert.AreEqual("a", data[0]); + Assert.AreEqual("b", data[1]); + Assert.AreEqual("c", data[2]); + Assert.AreEqual(3, data.Length); + + result = Arr.RemoveAt(ref data, -999); + Assert.AreEqual("a", result); + Assert.AreEqual("b", data[0]); + Assert.AreEqual("c", data[1]); + Assert.AreEqual(2, data.Length); + + result = Arr.RemoveAt(ref data, -1); + Assert.AreEqual("c", result); + Assert.AreEqual("b", data[0]); + Assert.AreEqual(1, data.Length); + + result = Arr.RemoveAt(ref data, -1); + Assert.AreEqual("b", result); + Assert.AreEqual(0, data.Length); + + data = new string[] { }; + result = Arr.RemoveAt(ref data, -1); + Assert.AreEqual(null, result); + Assert.AreEqual(0, data.Length); + } } } diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 7344d1d..c8255ef 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -964,48 +964,80 @@ private object ResloveClassAttr(Bindable makeServiceBindData, string servi return Make(makeServiceBindData.GetContextual(service)); } + /// + /// 从用户传入的参数中获取依赖 + /// + /// 基础参数 + /// 用户传入参数 + /// 合适的注入参数 + private object GetGetDependenciesFromUserParams(ParameterInfo baseParam, ref object[] userParams) + { + if (userParams == null) + { + return null; + } + + if (userParams.Length > 255) + { + throw new RuntimeException("Too many parameters , must be less than 255"); + } + + for (var n = 0; n < userParams.Length; n++) + { + var userParam = userParams[n]; + if (baseParam.ParameterType.IsInstanceOfType(userParam)) + { + return Arr.RemoveAt(ref userParams, n); + } + + try + { + if (baseParam.ParameterType.IsPrimitive) + { + var result = Convert.ChangeType(userParam, baseParam.ParameterType); + Arr.RemoveAt(ref userParams, n); + return result; + } + } + catch (Exception) + { + /* + throw new RuntimeException( + string.Format("Params [{0}({1})] can not convert to [{2}] , Service [{3}]", + baseParam.Name, userParam, baseParam.ParameterType, service + ), ex);*/ + } + } + + return null; + } + /// /// 获取依赖解决结果 /// /// 服务绑定数据 - /// 服务实例的参数信息 - /// 输入的构造参数列表 + /// 服务实例的参数信息 + /// 输入的构造参数列表 /// 服务所需参数的解决结果 /// 生成的实例类型和需求类型不一致 - private object[] GetDependencies(Bindable makeServiceBindData, IList paramInfo, IList param) where T : class, IBindable + private object[] GetDependencies(Bindable makeServiceBindData, IList baseParams, object[] userParams) where T : class, IBindable { - var myParam = new List(); + var results = new List(); - for (var i = 0; i < paramInfo.Count; i++) + foreach (var baseParam in baseParams) { - var info = paramInfo[i]; - if (param != null && i < param.Count) + var instance = GetGetDependenciesFromUserParams(baseParam, ref userParams); + if (instance != null) { - if (info.ParameterType.IsInstanceOfType(param[i])) - { - myParam.Add(param[i]); - continue; - } - - try - { - myParam.Add(Convert.ChangeType(param[i], info.ParameterType)); - } - catch (Exception ex) - { - throw new RuntimeException( - string.Format("Params [{0}({1})] can not convert to [{2}] , Service [{3}]", - info.Name, param[i], info.ParameterType, makeServiceBindData.Service - ), ex); - } + results.Add(instance); continue; } - var needService = Type2Service(info.ParameterType); + var needService = Type2Service(baseParam.ParameterType); InjectAttribute injectAttr = null; - if (info.IsDefined(injectTarget, false)) + if (baseParam.IsDefined(injectTarget, false)) { - var propertyAttrs = info.GetCustomAttributes(injectTarget, false); + var propertyAttrs = baseParam.GetCustomAttributes(injectTarget, false); if (propertyAttrs.Length > 0) { injectAttr = (InjectAttribute)propertyAttrs[0]; @@ -1016,8 +1048,7 @@ private object[] GetDependencies(Bindable makeServiceBindData, IList(Bindable makeServiceBindData, IList diff --git a/src/CatLib.Core/Support/Dispatcher/Dispatcher.cs b/src/CatLib.Core/Support/Dispatcher/Dispatcher.cs index 88f4913..ce1e56d 100644 --- a/src/CatLib.Core/Support/Dispatcher/Dispatcher.cs +++ b/src/CatLib.Core/Support/Dispatcher/Dispatcher.cs @@ -40,11 +40,17 @@ public sealed class Dispatcher : IDispatcher /// private readonly object breakFlag = false; + /// + /// 依赖注入容器 + /// + private IContainer container; + /// /// 调度器 /// - public Dispatcher() + public Dispatcher(IContainer container) { + this.container = container; handlers = new Dictionary>(); wildcardHandlers = new Dictionary>(); syncRoot = new object(); diff --git a/src/CatLib.Core/Support/Util/Arr.cs b/src/CatLib.Core/Support/Util/Arr.cs index 5f36cdd..19ab3d8 100644 --- a/src/CatLib.Core/Support/Util/Arr.cs +++ b/src/CatLib.Core/Support/Util/Arr.cs @@ -503,5 +503,21 @@ public static T[] Difference(T[] source, params T[] match) return true; }); } + + /// + /// 移除并返回指定下标的数组元素 + /// + /// 数组类型 + /// 规定数组 + /// 数组下标 + /// 被移除的元素 + public static T RemoveAt(ref T[] source, int index) + { + Guard.Requires(source != null); + Guard.Requires(index < source.Length); + + var result = Splice(ref source, index, 1); + return result.Length > 0 ? result[0] : default(T); + } } } \ No newline at end of file From 7a9956b76e0e9b30d1beac1dd28b95a902fbee29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Sat, 2 Dec 2017 13:44:33 +0800 Subject: [PATCH 11/91] add unit test --- .../Support/Container/ContainerTests.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs index d4769a5..8d55e68 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs @@ -624,6 +624,25 @@ public void CheckIllegalCallMethodParam() var result = container.Call(cls, "GetNumber", null); Assert.AreEqual(2, result); } + + [TestMethod] + public void TestOverflowParamNum() + { + var container = MakeContainer(); + var cls = new CallTestClass(); + + var isThrow = false; + try + { + container.Call(cls, "GetNumber", new object[256]); + } + catch (Exception ex) + { + isThrow = true; + } + + Assert.AreEqual(true, isThrow); + } #endregion #region Make From 50694f745b8a5b757b1498d85a9ddddb348968b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Sat, 2 Dec 2017 17:39:44 +0800 Subject: [PATCH 12/91] container optimization --- .../CatLib.Core.NetStandard.csproj | 10 +- .../Support/Container/ContainerTests.cs | 2 +- .../Support/Template/ManagerTests.cs | 2 +- src/CatLib.Core/CatLib.Core.csproj | 9 +- src/CatLib.Core/CatLib/App.cs | 139 +++- src/CatLib.Core/Support/Container/BindData.cs | 4 +- src/CatLib.Core/Support/Container/Bindable.cs | 2 +- .../Support/Container/Container.cs | 592 ++++++++++-------- .../Support/Container/IContainer.cs | 30 +- .../{Dispatcher => Events}/Dispatcher.cs | 0 .../{Dispatcher => Events}/EventHandler.cs | 0 src/CatLib.Core/Support/Events/EventMethod.cs | 59 ++ .../{Dispatcher => Events}/IDispatcher.cs | 0 .../{Dispatcher => Events}/IEventHandler.cs | 0 src/CatLib.Core/Support/Template/Managed.cs | 11 - src/CatLib.Core/Support/Util/Str.cs | 12 - 16 files changed, 540 insertions(+), 332 deletions(-) rename src/CatLib.Core/Support/{Dispatcher => Events}/Dispatcher.cs (100%) rename src/CatLib.Core/Support/{Dispatcher => Events}/EventHandler.cs (100%) create mode 100644 src/CatLib.Core/Support/Events/EventMethod.cs rename src/CatLib.Core/Support/{Dispatcher => Events}/IDispatcher.cs (100%) rename src/CatLib.Core/Support/{Dispatcher => Events}/IEventHandler.cs (100%) diff --git a/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj b/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj index 923b5a2..b091d94 100644 --- a/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj +++ b/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj @@ -78,10 +78,10 @@ - - - - + + + + @@ -118,7 +118,7 @@ - + diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs index 8d55e68..eadb483 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs @@ -735,7 +735,7 @@ public void MakeNoBindType() { var container = MakeContainer(); - //container.OnFindType(Type.GetType); 不要使用这种写法否则域将不是这个程序集 + //container.OnFindType(Type.GetServiceType); 不要使用这种写法否则域将不是这个程序集 container.OnFindType((str) => { return Type.GetType(str); diff --git a/src/CatLib.Core.Tests/Support/Template/ManagerTests.cs b/src/CatLib.Core.Tests/Support/Template/ManagerTests.cs index ee13d43..1472968 100644 --- a/src/CatLib.Core.Tests/Support/Template/ManagerTests.cs +++ b/src/CatLib.Core.Tests/Support/Template/ManagerTests.cs @@ -21,7 +21,7 @@ private class TestManagerClass : Manager { public Func GetResolvePublic(string name) { - return GetResolve(name); + return GetExtend(name); } } diff --git a/src/CatLib.Core/CatLib.Core.csproj b/src/CatLib.Core/CatLib.Core.csproj index cf1f071..f3595e0 100644 --- a/src/CatLib.Core/CatLib.Core.csproj +++ b/src/CatLib.Core/CatLib.Core.csproj @@ -50,10 +50,10 @@ - - - - + + + + @@ -65,6 +65,7 @@ + diff --git a/src/CatLib.Core/CatLib/App.cs b/src/CatLib.Core/CatLib/App.cs index d916bd9..c6b1b3b 100644 --- a/src/CatLib.Core/CatLib/App.cs +++ b/src/CatLib.Core/CatLib/App.cs @@ -329,11 +329,11 @@ public static IContainer OnRelease(Action action) /// /// 方法对象 /// 方法名 - /// 方法参数 + /// 用户传入的参数 /// 方法返回值 - public static object Call(object instance, string method, params object[] param) + public static object Call(object instance, string method, params object[] userParams) { - return Handler.Call(instance, method, param); + return Handler.Call(instance, method, userParams); } /// @@ -341,22 +341,102 @@ public static object Call(object instance, string method, params object[] param) /// /// 方法对象 /// 方法信息 - /// 方法参数 + /// 用户传入的参数 /// 方法返回值 - public static object Call(object instance, MethodInfo methodInfo, params object[] param) + public static object Call(object instance, MethodInfo methodInfo, params object[] userParams) { - return Handler.Call(instance, methodInfo, param); + return Handler.Call(instance, methodInfo, userParams); + } + + /// + /// 以依赖注入的形式调用一个方法 + /// + /// 方法 + public void Call(Action method) + { + Handler.Call(method); + } + + /// + /// 以依赖注入的形式调用一个方法 + /// + /// 方法 + public void Call(Action method) + { + Handler.Call(method); + } + + /// + /// 以依赖注入的形式调用一个方法 + /// + /// 方法 + public void Call(Action method) + { + Handler.Call(method); + } + + /// + /// 以依赖注入的形式调用一个方法 + /// + /// 方法 + public void Call(Action method) + { + Handler.Call(method); + } + + /// + /// 包装一个依赖注入形式调用的一个方法 + /// + /// 方法 + /// 用户传入的参数 + /// 包装方法 + public Action Wrap(Action method, params object[] userParams) + { + return Handler.Wrap(method, userParams); + } + + /// + /// 包装一个依赖注入形式调用的一个方法 + /// + /// 方法 + /// 用户传入的参数 + /// 包装方法 + public Action Wrap(Action method, params object[] userParams) + { + return Handler.Wrap(method, userParams); + } + + /// + /// 包装一个依赖注入形式调用的一个方法 + /// + /// 方法 + /// 用户传入的参数 + /// 包装方法 + public Action Wrap(Action method, params object[] userParams) + { + return Handler.Wrap(method, userParams); + } + + /// + /// 包装一个依赖注入形式调用的一个方法 + /// + /// 方法 + /// 用户传入的参数 + /// 包装方法 + public Action Wrap(Action method, params object[] userParams) + { + return Handler.Wrap(method, userParams); } /// /// 构造服务 /// /// 服务名或别名 - /// 构造参数 + /// 用户传入的参数 /// 服务实例,如果构造失败那么返回null - public static object MakeWith(string service, params object[] param) + public static object MakeWith(string service, params object[] userParams) { - return Handler.MakeWith(service, param); + return Handler.MakeWith(service, userParams); } /// @@ -369,6 +449,37 @@ public static object Make(string service) return Handler.Make(service); } + /// + /// 获取一个回调,当执行回调可以生成指定的服务 + /// + /// 服务名或别名 + /// 回调方案 + public static Func Factory(string service) + { + return Handler.Factory(service); + } + + /// + /// 获取一个回调,当执行回调可以生成指定的服务 + /// + /// 服务名 + /// 回调方案 + public static Func Factory() + { + return Handler.Factory(); + } + + /// + /// 获取一个回调,当执行回调可以生成指定的服务 + /// + /// 服务名 + /// 服务名或者别名 + /// 回调方案 + public static Func Factory(string service) + { + return Handler.Factory(service); + } + /// /// 为服务设定一个别名 /// @@ -531,16 +642,6 @@ public static TConvert Make(string service) return Handler.Make(service); } - /// - /// 释放服务 - /// - /// 服务名 - [Obsolete("This function is about to be removed , Please use Release()", true)] - public static void Releases() where TService : class - { - Handler.Release(); - } - /// /// 释放服务 /// diff --git a/src/CatLib.Core/Support/Container/BindData.cs b/src/CatLib.Core/Support/Container/BindData.cs index 17bff79..baa7047 100644 --- a/src/CatLib.Core/Support/Container/BindData.cs +++ b/src/CatLib.Core/Support/Container/BindData.cs @@ -17,7 +17,7 @@ namespace CatLib /// /// 服务绑定数据 /// - internal sealed class BindData : Bindable, IBindData + public sealed class BindData : Bindable, IBindData { /// /// 服务实现,执行这个委托将会获得服务实例 @@ -46,7 +46,7 @@ internal sealed class BindData : Bindable, IBindData /// 服务名 /// 服务实现 /// 服务是否是静态的 - internal BindData(Container container, string service, Func concrete, bool isStatic) + public BindData(Container container, string service, Func concrete, bool isStatic) :base(container, service) { Concrete = concrete; diff --git a/src/CatLib.Core/Support/Container/Bindable.cs b/src/CatLib.Core/Support/Container/Bindable.cs index 955365b..b69ffe1 100644 --- a/src/CatLib.Core/Support/Container/Bindable.cs +++ b/src/CatLib.Core/Support/Container/Bindable.cs @@ -16,7 +16,7 @@ namespace CatLib /// /// 可绑定对象 /// - internal abstract class Bindable : IBindable where TReturn : class, IBindable + public abstract class Bindable : IBindable where TReturn : class, IBindable { /// /// 当前绑定的名字 diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index c8255ef..40d3ec1 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -81,6 +81,11 @@ public class Container : IContainer /// private readonly Stack buildStack; + /// + /// 用户参数堆栈 + /// + private readonly Stack userParamsStack; + /// /// 构造一个容器 /// @@ -96,6 +101,7 @@ public Container() findType = new SortSet, int>(); injectTarget = typeof(InjectAttribute); buildStack = new Stack(); + userParamsStack = new Stack(); methodContainer = new MethodContainer(this); } @@ -168,7 +174,7 @@ public IBindData GetBind(string service) Guard.NotEmptyOrNull(service, "service"); lock (syncRoot) { - service = Normalize(service); + service = NormalizeService(service); service = AliasToService(service); BindData bindData; return binds.TryGetValue(service, out bindData) ? bindData : null; @@ -224,8 +230,8 @@ public IContainer Alias(string alias, string service) throw new RuntimeException("Alias is Same as Service Name: [" + alias + "]."); } - alias = Normalize(alias); - service = Normalize(service); + alias = NormalizeService(alias); + service = NormalizeService(service); lock (syncRoot) { @@ -294,7 +300,7 @@ public IBindData Bind(string service, Type concrete, bool isStatic) return Bind(service, (c, param) => { var container = (Container)c; - return container.BuildMake(service, concrete, false, param); + return container.Resolve(service, concrete, false, param); }, isStatic); } @@ -311,7 +317,7 @@ public IBindData Bind(string service, Func concret { Guard.NotEmptyOrNull(service, "service"); Guard.NotNull(concrete, "concrete"); - service = Normalize(service); + service = NormalizeService(service); lock (syncRoot) { if (binds.ContainsKey(service)) @@ -341,16 +347,16 @@ public IBindData Bind(string service, Func concret /// /// 方法对象 /// 方法名 - /// 附加的参数 + /// 用户传入的参数 /// 方法返回值 /// ,null或者空字符串 - public object Call(object instance, string method, params object[] param) + public object Call(object instance, string method, params object[] userParams) { Guard.NotNull(instance, "instance"); Guard.NotEmptyOrNull(method, "method"); var methodInfo = instance.GetType().GetMethod(method); - return Call(instance, methodInfo, param); + return Call(instance, methodInfo, userParams); } /// @@ -358,10 +364,10 @@ public object Call(object instance, string method, params object[] param) /// /// 方法对象 /// 方法信息 - /// 方法参数 + /// 用户传入的参数 /// 方法返回值 /// ,null - public object Call(object instance, MethodInfo methodInfo, params object[] param) + public object Call(object instance, MethodInfo methodInfo, params object[] userParams) { Guard.NotNull(instance, "instance"); Guard.NotNull(methodInfo, "methodInfo"); @@ -371,9 +377,9 @@ public object Call(object instance, MethodInfo methodInfo, params object[] param lock (syncRoot) { - var bindData = GetBindData(Type2Service(type)); - param = parameter.Count > 0 ? GetDependencies(bindData, parameter, param) : new object[] { }; - return methodInfo.Invoke(instance, param); + var bindData = GetBindFillable(Type2Service(type)); + userParams = parameter.Count > 0 ? GetDependencies(bindData, parameter, userParams) : new object[] { }; + return methodInfo.Invoke(instance, userParams); } } @@ -421,15 +427,15 @@ public void Call(Action method) /// 包装一个依赖注入形式调用的一个方法 /// /// 方法 - /// 方法参数 + /// 用户传入的参数 /// 包装方法 - public Action Wrap(Action method, params object[] param) + public Action Wrap(Action method, params object[] userParams) { return () => { if (method != null) { - Call(method.Target, method.Method, param); + Call(method.Target, method.Method, userParams); } }; } @@ -438,15 +444,15 @@ public Action Wrap(Action method, params object[] param) /// 包装一个依赖注入形式调用的一个方法 /// /// 方法 - /// 方法参数 + /// 用户传入的参数 /// 包装方法 - public Action Wrap(Action method, params object[] param) + public Action Wrap(Action method, params object[] userParams) { return () => { if (method != null) { - Call(method.Target, method.Method, param); + Call(method.Target, method.Method, userParams); } }; } @@ -455,15 +461,15 @@ public Action Wrap(Action method, params object[] param) /// 包装一个依赖注入形式调用的一个方法 /// /// 方法 - /// 方法参数 + /// 用户传入的参数 /// 包装方法 - public Action Wrap(Action method, params object[] param) + public Action Wrap(Action method, params object[] userParams) { return () => { if (method != null) { - Call(method.Target, method.Method, param); + Call(method.Target, method.Method, userParams); } }; } @@ -472,15 +478,15 @@ public Action Wrap(Action method, params object[] param) /// 包装一个依赖注入形式调用的一个方法 /// /// 方法 - /// 方法参数 + /// 用户传入的参数 /// 包装方法 - public Action Wrap(Action method, params object[] param) + public Action Wrap(Action method, params object[] userParams) { return () => { if (method != null) { - Call(method.Target, method.Method, param); + Call(method.Target, method.Method, userParams); } }; } @@ -489,17 +495,17 @@ public Action Wrap(Action method, params object[ /// 构造服务 /// /// 服务名或别名 - /// 构造参数 + /// 用户传入的构造参数 /// 服务实例,如果构造失败那么返回null /// null或者空字符串 /// 出现循环依赖 /// 服务实例,如果构造失败那么返回null - public object MakeWith(string service, params object[] param) + public object MakeWith(string service, params object[] userParams) { Guard.NotEmptyOrNull(service, "service"); lock (syncRoot) { - service = Normalize(service); + service = NormalizeService(service); service = AliasToService(service); object instance; @@ -514,12 +520,14 @@ public object MakeWith(string service, params object[] param) } buildStack.Push(service); + userParamsStack.Push(userParams); try { - return BuildMake(service, null, true, param); + return Resolve(service, null, true, userParams); } finally { + userParamsStack.Pop(); buildStack.Pop(); } } @@ -569,7 +577,7 @@ public void Instance(string service, object instance) Guard.NotEmptyOrNull(service, "service"); lock (syncRoot) { - service = Normalize(service); + service = NormalizeService(service); service = AliasToService(service); var bindData = GetBind(service); @@ -588,7 +596,7 @@ public void Instance(string service, object instance) Release(service); - instance = ExecOnResolvingDecorator(bindData, instance); + instance = TriggerOnResolving(bindData, instance); instances.Add(service, instance); } } @@ -602,7 +610,7 @@ public void Release(string service) Guard.NotEmptyOrNull(service, "service"); lock (syncRoot) { - service = Normalize(service); + service = NormalizeService(service); service = AliasToService(service); object instance; @@ -611,9 +619,9 @@ public void Release(string service) return; } - var bindData = GetBindData(service); + var bindData = GetBindFillable(service); bindData.ExecReleaseDecorator(instance); - ExecOnReleaseDecorator(bindData, instance); + TriggerOnRelease(bindData, instance); instances.Remove(service); } } @@ -693,7 +701,7 @@ public IContainer OnResolving(Func func) var result = new Dictionary(); foreach (var data in instances) { - var bindData = GetBindData(data.Key); + var bindData = GetBindFillable(data.Key); result[data.Key] = func.Invoke(bindData, data.Value); } foreach (var data in result) @@ -705,15 +713,25 @@ public IContainer OnResolving(Func func) return this; } + /// + /// 将类型转为服务名 + /// + /// 类型 + /// 服务名 + public string Type2Service(Type type) + { + return type.ToString(); + } + /// /// 解除绑定服务 /// /// 服务名或者别名 - internal void UnBind(string service) + public void UnBind(string service) { lock (syncRoot) { - service = Normalize(service); + service = NormalizeService(service); service = AliasToService(service); Release(service); @@ -731,108 +749,19 @@ internal void UnBind(string service) } /// - /// 将类型转为服务名 - /// - /// 类型 - /// 服务名 - public string Type2Service(Type type) - { - return type.ToString(); - } - - /// - /// 执行全局解决修饰器 - /// - /// 服务绑定数据 - /// 服务实例 - /// 被修饰器修饰后的服务实例 - private object ExecOnResolvingDecorator(IBindData bindData, object obj) - { - foreach (var func in resolving) - { - obj = func(bindData, obj); - } - return obj; - } - - /// - /// 执行全局释放修饰器 - /// - /// 服务绑定数据 - /// 服务实例 - /// 被修饰器修饰后的服务实例 - private void ExecOnReleaseDecorator(IBindData bindData, object obj) - { - foreach (var action in release) - { - action.Invoke(bindData, obj); - } - } - - /// - /// 构造服务 - /// - /// 服务名 - /// 服务类型 - /// 是否直接调用自Make函数 - /// 构造参数 - /// 服务实例 - private object BuildMake(string makeService, Type makeServiceType, bool isFromMake, params object[] param) - { - var bindData = GetBindData(makeService); - var buildInstance = isFromMake ? BuildUseConcrete(bindData, makeServiceType, param) : Build(bindData, makeServiceType ?? GetType(bindData.Service), param); - - //只有是来自于make函数的调用时才执行di,包装,以及修饰 - if (!isFromMake) - { - return buildInstance; - } - - AttrInject(bindData, buildInstance); - - if (bindData.IsStatic) - { - Instance(makeService, buildInstance); - } - else - { - buildInstance = ExecOnResolvingDecorator(bindData, bindData.ExecResolvingDecorator(buildInstance)); - } - - return buildInstance; - } - - /// - /// 常规编译一个服务 - /// - /// 服务绑定数据 - /// 服务类型 - /// 构造参数 - /// 服务实例 - private object BuildUseConcrete(BindData makeServiceBindData, Type makeServiceType, object[] param) - { - return makeServiceBindData.Concrete != null ? - makeServiceBindData.Concrete(this, param) : - BuildMake(makeServiceBindData.Service, makeServiceType, false, param); - } - - /// - /// 构造服务 - 实现 + /// 构造服务实现 /// /// 服务绑定数据 /// 服务类型 - /// 构造参数 + /// 用户传入的构造参数 /// 服务实例 - private object Build(BindData makeServiceBindData, Type makeServiceType, object[] param) + protected object Build(BindData makeServiceBindData, Type makeServiceType, object[] userParams) { - param = param ?? new object[] { }; - - if (makeServiceType == null) - { - return null; - } + userParams = userParams ?? new object[] { }; - if (makeServiceType.IsAbstract || makeServiceType.IsInterface) + if (makeServiceType == null + || makeServiceType.IsAbstract + || makeServiceType.IsInterface) { return null; } @@ -846,7 +775,7 @@ private object Build(BindData makeServiceBindData, Type makeServiceType, object[ } catch (Exception ex) { - throw ThrowBuildFaild(makeServiceType, ex); + throw MakeBuildFaildException(makeServiceType, ex); } } @@ -854,40 +783,19 @@ private object Build(BindData makeServiceBindData, Type makeServiceType, object[ if (parameter.Count > 0) { - param = GetDependencies(makeServiceBindData, parameter, param); + userParams = GetDependencies(makeServiceBindData, parameter, userParams); } try { - return Activator.CreateInstance(makeServiceType, param); + return Activator.CreateInstance(makeServiceType, userParams); } catch (Exception ex) { - throw ThrowBuildFaild(makeServiceType, ex); + throw MakeBuildFaildException(makeServiceType, ex); } } - /// - /// 触发编译异常 - /// - /// 构造的服务类型 - /// 异常 - /// 运行时异常 - private RuntimeException ThrowBuildFaild(Type makeServiceType, Exception ex) - { - return new RuntimeException("Build [" + makeServiceType + "] faild", ex); - } - - /// - /// 标准化服务名 - /// - /// 服务名 - /// 标准化后的服务名 - private string Normalize(string service) - { - return service.Trim(); - } - /// /// 属性注入 /// @@ -895,7 +803,7 @@ private string Normalize(string service) /// 服务实例 /// 服务实例 /// 属性是必须的或者注入类型和需求类型不一致 - private void AttrInject(Bindable makeServiceBindData, object makeServiceInstance) where T : class , IBindable + protected void AttributeInject(Bindable makeServiceBindData, object makeServiceInstance) where T : class , IBindable { if (makeServiceInstance == null) { @@ -904,36 +812,32 @@ private void AttrInject(Bindable makeServiceBindData, object makeServiceIn foreach (var property in makeServiceInstance.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)) { - if (!property.CanWrite) + if (!property.CanWrite + || !property.IsDefined(injectTarget, false)) { continue; } - if (!property.IsDefined(injectTarget, false)) - { - continue; - } + InjectAttribute injectAttr = null; + var needService = GetPropertyNeedsService(property, ref injectAttr); - var injectAttr = (InjectAttribute)property.GetCustomAttributes(injectTarget, false)[0]; - var needService = string.IsNullOrEmpty(injectAttr.Alias) - ? Type2Service(property.PropertyType) - : injectAttr.Alias; object instance; - if (property.PropertyType.IsClass || property.PropertyType.IsInterface) + if (property.PropertyType.IsClass + || property.PropertyType.IsInterface) { - instance = ResloveClassAttr(makeServiceBindData, needService); + instance = ResloveAttrClass(makeServiceBindData, needService, property); } else { - instance = ResolveNonClassAttr(makeServiceBindData, needService); + instance = ResolveAttrPrimitive(makeServiceBindData, needService, property); } - if (injectAttr.Required && instance == null) + if (!CheckInjectAttrRequired(injectAttr, instance)) { throw new RuntimeException("[" + makeServiceBindData.Service + "] Attr [" + property.PropertyType + "] Required [" + needService + "] Service."); } - if (instance != null && !property.PropertyType.IsInstanceOfType(instance)) + if (!CheckInstanceIsInstanceOfType(property.PropertyType, instance)) { throw new RuntimeException("[" + makeServiceBindData.Service + "] Attr inject type must be [" + property.PropertyType + "] , But instance is [" + instance.GetType() + "] , Make service is [" + needService + "]."); } @@ -943,25 +847,53 @@ private void AttrInject(Bindable makeServiceBindData, object makeServiceIn } /// - /// 解决非类类型 + /// 获取依赖解决结果 /// - /// 请求注入操作的服务绑定数据 - /// 希望构造的服务名或者别名 - /// 解决结果 - private object ResolveNonClassAttr(Bindable makeServiceBindData, string service) where T : class, IBindable + /// 服务绑定数据 + /// 服务实例的参数信息 + /// 输入的构造参数列表 + /// 服务所需参数的解决结果 + /// 生成的实例类型和需求类型不一致 + protected object[] GetDependencies(Bindable makeServiceBindData, IList baseParams, object[] userParams) where T : class, IBindable { - return Make(makeServiceBindData.GetContextual(service)); - } + var results = new List(); - /// - /// 解决类类型 - /// - /// 请求注入操作的服务绑定数据 - /// 希望构造的服务名或者别名 - /// 解决结果 - private object ResloveClassAttr(Bindable makeServiceBindData, string service) where T : class, IBindable - { - return Make(makeServiceBindData.GetContextual(service)); + foreach (var baseParam in baseParams) + { + var instance = GetDependenciesFromUserParams(baseParam, ref userParams); + if (instance != null) + { + results.Add(instance); + continue; + } + + InjectAttribute injectAttr = null; + var needService = GetParamNeedsService(baseParam, ref injectAttr); + + if (baseParam.ParameterType.IsClass + || baseParam.ParameterType.IsInterface) + { + instance = ResloveClass(makeServiceBindData, needService, baseParam); + } + else + { + instance = ResolvePrimitive(makeServiceBindData, needService, baseParam); + } + + if (!CheckInjectAttrRequired(injectAttr, instance)) + { + throw new RuntimeException("[" + makeServiceBindData.Service + "] Required [" + baseParam.ParameterType + "] Service."); + } + + if (!CheckInstanceIsInstanceOfType(baseParam.ParameterType, instance)) + { + throw new RuntimeException("[" + makeServiceBindData.Service + "] Params inject type must be [" + baseParam.ParameterType + "] , But instance is [" + instance.GetType() + "] Make service is [" + needService + "]."); + } + + results.Add(instance); + } + + return results.ToArray(); } /// @@ -970,17 +902,14 @@ private object ResloveClassAttr(Bindable makeServiceBindData, string servi /// 基础参数 /// 用户传入参数 /// 合适的注入参数 - private object GetGetDependenciesFromUserParams(ParameterInfo baseParam, ref object[] userParams) + protected object GetDependenciesFromUserParams(ParameterInfo baseParam, ref object[] userParams) { if (userParams == null) { return null; } - if (userParams.Length > 255) - { - throw new RuntimeException("Too many parameters , must be less than 255"); - } + GuardUserParamsCount(userParams.Length); for (var n = 0; n < userParams.Length; n++) { @@ -992,7 +921,7 @@ private object GetGetDependenciesFromUserParams(ParameterInfo baseParam, ref obj try { - if (baseParam.ParameterType.IsPrimitive) + if (baseParam.ParameterType.IsPrimitive && userParam is IConvertible) { var result = Convert.ChangeType(userParam, baseParam.ParameterType); Arr.RemoveAt(ref userParams, n); @@ -1013,73 +942,75 @@ private object GetGetDependenciesFromUserParams(ParameterInfo baseParam, ref obj } /// - /// 获取依赖解决结果 + /// 获取字段需求服务 /// - /// 服务绑定数据 - /// 服务实例的参数信息 - /// 输入的构造参数列表 - /// 服务所需参数的解决结果 - /// 生成的实例类型和需求类型不一致 - private object[] GetDependencies(Bindable makeServiceBindData, IList baseParams, object[] userParams) where T : class, IBindable + /// 字段 + /// 依赖注入标记 + /// 需求的服务名 + protected string GetPropertyNeedsService(PropertyInfo property, ref InjectAttribute injectAttr) { - var results = new List(); + injectAttr = (InjectAttribute)property.GetCustomAttributes(injectTarget, false)[0]; + return string.IsNullOrEmpty(injectAttr.Alias) + ? Type2Service(property.PropertyType) + : injectAttr.Alias; + } - foreach (var baseParam in baseParams) + /// + /// 获取参数需求服务 + /// + /// 当前正在解决的变量 + /// 依赖注入标记 + /// 需求的服务名 + protected string GetParamNeedsService(ParameterInfo baseParam, ref InjectAttribute injectAttr) + { + var needService = Type2Service(baseParam.ParameterType); + if (baseParam.IsDefined(injectTarget, false)) { - var instance = GetGetDependenciesFromUserParams(baseParam, ref userParams); - if (instance != null) + var propertyAttrs = baseParam.GetCustomAttributes(injectTarget, false); + if (propertyAttrs.Length > 0) { - results.Add(instance); - continue; - } - - var needService = Type2Service(baseParam.ParameterType); - InjectAttribute injectAttr = null; - if (baseParam.IsDefined(injectTarget, false)) - { - var propertyAttrs = baseParam.GetCustomAttributes(injectTarget, false); - if (propertyAttrs.Length > 0) + injectAttr = (InjectAttribute)propertyAttrs[0]; + if (!string.IsNullOrEmpty(injectAttr.Alias)) { - injectAttr = (InjectAttribute)propertyAttrs[0]; - if (!string.IsNullOrEmpty(injectAttr.Alias)) - { - needService = injectAttr.Alias; - } + needService = injectAttr.Alias; } } - - if (baseParam.ParameterType.IsClass || baseParam.ParameterType.IsInterface) - { - instance = ResloveClass(makeServiceBindData, needService); - } - else - { - instance = ResolveNonClass(makeServiceBindData, needService); - } - - if (injectAttr != null && injectAttr.Required && instance == null) - { - throw new RuntimeException("[" + makeServiceBindData.Service + "] Required [" + baseParam.ParameterType + "] Service."); - } - - if (instance != null && !baseParam.ParameterType.IsInstanceOfType(instance)) - { - throw new RuntimeException("[" + makeServiceBindData.Service + "] Attr inject type must be [" + baseParam.ParameterType + "] , But instance is [" + instance.GetType() + "] Make service is [" + needService + "]."); - } - - results.Add(instance); } + return needService; + } - return results.ToArray(); + /// + /// 解决基本类型 + /// + /// 请求注入操作的服务绑定数据 + /// 希望解决的服务名或者别名 + /// 当前正在解决的变量 + /// 解决结果 + protected object ResolveAttrPrimitive(Bindable makeServiceBindData, string service, PropertyInfo baseParam) where T : class, IBindable + { + return Make(makeServiceBindData.GetContextual(service)); + } + + /// + /// 解决类类型 + /// + /// 请求注入操作的服务绑定数据 + /// 希望解决的服务名或者别名 + /// 当前正在解决的变量 + /// 解决结果 + protected object ResloveAttrClass(Bindable makeServiceBindData, string service, PropertyInfo baseParam) where T : class, IBindable + { + return Make(makeServiceBindData.GetContextual(service)); } /// - /// 解决非类类型 + /// 解决基本类型 /// /// 请求注入操作的服务绑定数据 /// 希望解决的服务名或者别名 + /// 当前正在解决的变量 /// 解决结果 - private object ResolveNonClass(Bindable makeServiceBindData, string service) where T : class, IBindable + protected object ResolvePrimitive(Bindable makeServiceBindData, string service , ParameterInfo baseParam) where T : class, IBindable { return Make(makeServiceBindData.GetContextual(service)); } @@ -1089,32 +1020,40 @@ private object ResolveNonClass(Bindable makeServiceBindData, string servic /// /// 请求注入操作的服务绑定数据 /// 希望解决的服务名或者别名 + /// 当前正在解决的变量 /// 解决结果 - private object ResloveClass(Bindable makeServiceBindData, string service) where T : class, IBindable + protected object ResloveClass(Bindable makeServiceBindData, string service, ParameterInfo baseParam) where T : class, IBindable { return Make(makeServiceBindData.GetContextual(service)); } /// - /// 获取别名最终对应的服务名 + /// 触发全局解决修饰器 /// - /// 服务名或别名 - /// 最终映射的服务名 - private string AliasToService(string service) + /// 服务绑定数据 + /// 服务实例 + /// 被修饰器修饰后的服务实例 + protected object TriggerOnResolving(IBindData bindData, object obj) { - string alias; - return aliases.TryGetValue(service, out alias) ? alias : service; + foreach (var func in resolving) + { + obj = func(bindData, obj); + } + return obj; } /// - /// 获取服务绑定数据(与GetBind的区别是永远不会为null) + /// 触发全局释放修饰器 /// - /// 服务名 - /// 服务绑定数据 - private BindData GetBindData(string service) + /// 服务绑定数据 + /// 服务实例 + /// 被修饰器修饰后的服务实例 + protected void TriggerOnRelease(IBindData bindData, object obj) { - BindData bindData; - return binds.TryGetValue(service, out bindData) ? bindData : MakeEmptyBindData(service); + foreach (var action in release) + { + action.Invoke(bindData, obj); + } } /// @@ -1122,17 +1061,78 @@ private BindData GetBindData(string service) /// /// 服务名 /// 空绑定数据 - private BindData MakeEmptyBindData(string service) + protected BindData MakeEmptyBindData(string service) { return new BindData(this, service, null, false); } /// - /// 获取类型映射 + /// 生成一个编译失败异常 + /// + /// 构造的服务类型 + /// 内部异常 + /// 运行时异常 + protected RuntimeException MakeBuildFaildException(Type makeServiceType, Exception innerException) + { + var message = "Target [" + makeServiceType + "] build faild."; + if (buildStack.Count > 0) + { + var previous = string.Join(", ", buildStack.ToArray()); + message = "Target [" + makeServiceType + "] build faild while building [" + previous + "]."; + } + return new RuntimeException(message, innerException); + } + + /// + /// 标准化服务名 + /// + /// 服务名 + /// 标准化后的服务名 + protected string NormalizeService(string service) + { + return service.Trim(); + } + + /// + /// 检查实例是否实现自某种类型 + /// + /// 需要实现自的类型 + /// 生成的实例 + /// 是否符合类型 + protected bool CheckInstanceIsInstanceOfType(Type type, object instance) + { + return instance == null || type.IsInstanceOfType(instance); + } + + /// + /// 检查依赖注入的必须标记 + /// + /// 依赖注入标记 + /// 生成的实例 + /// 是否通过检查 + protected bool CheckInjectAttrRequired(InjectAttribute injectAttr, object instance) + { + return injectAttr == null || !injectAttr.Required || instance != null; + } + + /// + /// 保证用户传入参数必须小于指定值 + /// + /// 传入参数数量 + protected void GuardUserParamsCount(int count) + { + if (count > 255) + { + throw new RuntimeException("Too many parameters , must be less than 255"); + } + } + + /// + /// 获取通过服务名获取服务的类型 /// /// 服务名 /// 服务类型 - private Type GetType(string service) + protected Type GetServiceType(string service) { foreach (var finder in findType) { @@ -1144,5 +1144,75 @@ private Type GetType(string service) } return null; } + + /// + /// 解决服务 + /// + /// 服务名 + /// 服务类型 + /// 是否直接调用自Make函数 + /// 用户传入的构造参数 + /// 服务实例 + private object Resolve(string makeService, Type makeServiceType, bool isFromMake, params object[] userParams) + { + var bindData = GetBindFillable(makeService); + var buildInstance = isFromMake ? BuildUseConcrete(bindData, makeServiceType, userParams) + : Build(bindData, makeServiceType ?? GetServiceType(bindData.Service), userParams); + + //只有是来自于make函数的调用时才执行di,包装,以及修饰 + if (!isFromMake) + { + return buildInstance; + } + + AttributeInject(bindData, buildInstance); + + if (bindData.IsStatic) + { + Instance(makeService, buildInstance); + } + else + { + buildInstance = TriggerOnResolving(bindData, bindData.ExecResolvingDecorator(buildInstance)); + } + + return buildInstance; + } + + /// + /// 常规编译一个服务 + /// + /// 服务绑定数据 + /// 服务类型 + /// 构造参数 + /// 服务实例 + private object BuildUseConcrete(BindData makeServiceBindData, Type makeServiceType, object[] param) + { + return makeServiceBindData.Concrete != null ? + makeServiceBindData.Concrete(this, param) : + Resolve(makeServiceBindData.Service, makeServiceType, false, param); + } + + /// + /// 获取别名最终对应的服务名 + /// + /// 服务名或别名 + /// 最终映射的服务名 + private string AliasToService(string service) + { + string alias; + return aliases.TryGetValue(service, out alias) ? alias : service; + } + + /// + /// 获取服务绑定数据,如果数据为null则填充数据 + /// + /// 服务名 + /// 服务绑定数据 + private BindData GetBindFillable(string service) + { + BindData bindData; + return binds.TryGetValue(service, out bindData) ? bindData : MakeEmptyBindData(service); + } } } \ No newline at end of file diff --git a/src/CatLib.Core/Support/Container/IContainer.cs b/src/CatLib.Core/Support/Container/IContainer.cs index 0952d76..24038ca 100644 --- a/src/CatLib.Core/Support/Container/IContainer.cs +++ b/src/CatLib.Core/Support/Container/IContainer.cs @@ -15,7 +15,7 @@ namespace CatLib { /// - /// 容器接口 + /// 依赖注入容器 /// public interface IContainer { @@ -126,18 +126,18 @@ public interface IContainer /// /// 方法对象 /// 方法名 - /// 方法参数 + /// 用户传入的参数 /// 方法返回值 - object Call(object instance, string method, params object[] param); + object Call(object instance, string method, params object[] userParams); /// /// 以依赖注入形式调用一个方法 /// /// 方法对象 /// 方法信息 - /// 方法参数 + /// 用户传入的参数 /// 方法返回值 - object Call(object instance, MethodInfo methodInfo, params object[] param); + object Call(object instance, MethodInfo methodInfo, params object[] userParams); /// /// 以依赖注入的形式调用一个方法 @@ -167,41 +167,41 @@ public interface IContainer /// 包装一个依赖注入形式调用的一个方法 /// /// 方法 - /// 方法参数 + /// 用户传入的参数 /// 包装方法 - Action Wrap(Action method, params object[] param); + Action Wrap(Action method, params object[] userParams); /// /// 包装一个依赖注入形式调用的一个方法 /// /// 方法 - /// 方法参数 + /// 用户传入的参数 /// 包装方法 - Action Wrap(Action method, params object[] param); + Action Wrap(Action method, params object[] userParams); /// /// 包装一个依赖注入形式调用的一个方法 /// /// 方法 - /// 方法参数 + /// 用户传入的参数 /// 包装方法 - Action Wrap(Action method, params object[] param); + Action Wrap(Action method, params object[] userParams); /// /// 包装一个依赖注入形式调用的一个方法 /// /// 方法 - /// 方法参数 + /// 用户传入的参数 /// 包装方法 - Action Wrap(Action method, params object[] param); + Action Wrap(Action method, params object[] userParams); /// /// 构造服务,允许传入参数来决定构造函数的值 /// /// 服务名或别名 - /// 构造参数 + /// 用户传入的参数 /// 服务实例,如果构造失败那么返回null - object MakeWith(string service, params object[] param); + object MakeWith(string service, params object[] userParams); /// /// 构造服务 diff --git a/src/CatLib.Core/Support/Dispatcher/Dispatcher.cs b/src/CatLib.Core/Support/Events/Dispatcher.cs similarity index 100% rename from src/CatLib.Core/Support/Dispatcher/Dispatcher.cs rename to src/CatLib.Core/Support/Events/Dispatcher.cs diff --git a/src/CatLib.Core/Support/Dispatcher/EventHandler.cs b/src/CatLib.Core/Support/Events/EventHandler.cs similarity index 100% rename from src/CatLib.Core/Support/Dispatcher/EventHandler.cs rename to src/CatLib.Core/Support/Events/EventHandler.cs diff --git a/src/CatLib.Core/Support/Events/EventMethod.cs b/src/CatLib.Core/Support/Events/EventMethod.cs new file mode 100644 index 0000000..99a06f6 --- /dev/null +++ b/src/CatLib.Core/Support/Events/EventMethod.cs @@ -0,0 +1,59 @@ +/* + * 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.Reflection; + +namespace CatLib +{ + /// + /// 事件方法 + /// + internal sealed class EventMethod + { + /// + /// 依赖注入容器 + /// + private readonly IContainer container; + + /// + /// 方法 + /// + private readonly MethodInfo method; + + /// + /// 实例目标 + /// + private readonly object target; + + /// + /// 创建一个事件句柄 + /// + /// 依赖注入容器 + /// 调用源 + /// 调用方法名 + internal EventMethod(IContainer container, object target, string method) + { + this.container = container; + this.target = target; + this.method = target.GetType().GetMethod(method, + BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy); + } + + /// + /// 调用方法 + /// + /// 方法参数 + public object Call(params object[] args) + { + return container.Call(target, method, args); + } + } +} diff --git a/src/CatLib.Core/Support/Dispatcher/IDispatcher.cs b/src/CatLib.Core/Support/Events/IDispatcher.cs similarity index 100% rename from src/CatLib.Core/Support/Dispatcher/IDispatcher.cs rename to src/CatLib.Core/Support/Events/IDispatcher.cs diff --git a/src/CatLib.Core/Support/Dispatcher/IEventHandler.cs b/src/CatLib.Core/Support/Events/IEventHandler.cs similarity index 100% rename from src/CatLib.Core/Support/Dispatcher/IEventHandler.cs rename to src/CatLib.Core/Support/Events/IEventHandler.cs diff --git a/src/CatLib.Core/Support/Template/Managed.cs b/src/CatLib.Core/Support/Template/Managed.cs index 8830ada..d0da618 100644 --- a/src/CatLib.Core/Support/Template/Managed.cs +++ b/src/CatLib.Core/Support/Template/Managed.cs @@ -64,17 +64,6 @@ public bool ContainsExtend(string name = null) return resolve.ContainsKey(name); } - /// - /// 获取解决方案 - /// - /// 名字 - /// 拓展 - [Obsolete("Please use GetExtend()")] - protected Func GetResolve(string name) - { - return GetExtend(name); - } - /// /// 获取解决方案拓展 /// diff --git a/src/CatLib.Core/Support/Util/Str.cs b/src/CatLib.Core/Support/Util/Str.cs index 521593e..3416630 100644 --- a/src/CatLib.Core/Support/Util/Str.cs +++ b/src/CatLib.Core/Support/Util/Str.cs @@ -67,18 +67,6 @@ public static string AsteriskWildcard(string pattern) return pattern; } - /// - /// 为每个正则表达式语法中的字符前增加一个反斜线。 - /// - /// 规定字符串 - /// 处理后的字符串 - [Obsolete("Please use Regex.Escape()")] - [ExcludeFromCodeCoverage] - public static string RegexQuote(string str) - { - return Regex.Escape(str); - } - /// /// 根据长度将字符串分割到数组中 /// From dd7ea7a572bb431c8ff74ea732b794dc23ac0452 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Sat, 2 Dec 2017 17:52:17 +0800 Subject: [PATCH 13/91] container test update --- .../Support/Container/ContainerTests.cs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs index eadb483..fe6dd5d 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs @@ -643,6 +643,28 @@ public void TestOverflowParamNum() Assert.AreEqual(true, isThrow); } + + class SimpleTestClass1 { } + class SimpleTestClass2 { } + + [TestMethod] + public void TestLooseParameters() + { + var container = MakeContainer(); + container.Bind(); + container.Bind(); + + var objOut = new object(); + var call = container.Wrap((object obj, SimpleTestClass1 cls1, int num, SimpleTestClass2 cls2) => + { + Assert.AreSame(objOut, obj); + Assert.AreNotEqual(null, cls1); + Assert.AreNotEqual(null, cls2); + Assert.AreEqual(100, num); + }, objOut, (long)100); + + call.Invoke(); + } #endregion #region Make From 22532e7ac805b1ac160fd05a8a7f37c8c72ac305 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Sat, 2 Dec 2017 19:03:36 +0800 Subject: [PATCH 14/91] container optimization --- .../Support/Container/BindDataTests.cs | 2 +- src/CatLib.Core/Support/Container/BindData.cs | 4 ++-- src/CatLib.Core/Support/Container/Container.cs | 17 ++++++++++++++--- src/CatLib.Core/Support/Events/EventMethod.cs | 2 +- 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/CatLib.Core.Tests/Support/Container/BindDataTests.cs b/src/CatLib.Core.Tests/Support/Container/BindDataTests.cs index 579b31d..0d1a115 100644 --- a/src/CatLib.Core.Tests/Support/Container/BindDataTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/BindDataTests.cs @@ -174,7 +174,7 @@ public void CanAddOnResolving() bindData.OnResolving((bind, obj) => null); - var data = bindData.ExecResolvingDecorator(new Container()); + var data = bindData.TriggerResolving(new Container()); Assert.AreEqual(null, data); } diff --git a/src/CatLib.Core/Support/Container/BindData.cs b/src/CatLib.Core/Support/Container/BindData.cs index baa7047..dffe1b0 100644 --- a/src/CatLib.Core/Support/Container/BindData.cs +++ b/src/CatLib.Core/Support/Container/BindData.cs @@ -136,7 +136,7 @@ protected override void ReleaseBind() /// /// 服务实例 /// 修饰后的服务实例 - internal object ExecResolvingDecorator(object obj) + internal object TriggerResolving(object obj) { if (resolving == null) { @@ -153,7 +153,7 @@ internal object ExecResolvingDecorator(object obj) /// 执行服务释放处理器 /// /// 服务实例 - internal void ExecReleaseDecorator(object obj) + internal void TriggerRelease(object obj) { if (release == null) { diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 40d3ec1..3c296a0 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -587,7 +587,7 @@ public void Instance(string service, object instance) { throw new RuntimeException("Service [" + service + "] is not Singleton(Static) Bind."); } - instance = ((BindData)bindData).ExecResolvingDecorator(instance); + instance = ((BindData)bindData).TriggerResolving(instance); } else { @@ -620,7 +620,7 @@ public void Release(string service) } var bindData = GetBindFillable(service); - bindData.ExecReleaseDecorator(instance); + bindData.TriggerRelease(instance); TriggerOnRelease(bindData, instance); instances.Remove(service); } @@ -1012,6 +1012,17 @@ protected object ResloveAttrClass(Bindable makeServiceBindData, string ser /// 解决结果 protected object ResolvePrimitive(Bindable makeServiceBindData, string service , ParameterInfo baseParam) where T : class, IBindable { + var newServiceBind = GetBind(makeServiceBindData.GetContextual("@" + baseParam.Name)); + if (newServiceBind != null) + { + return Make(newServiceBind.Service); + } + + if (baseParam.DefaultValue != DBNull.Value) + { + return baseParam.DefaultValue; + } + return Make(makeServiceBindData.GetContextual(service)); } @@ -1173,7 +1184,7 @@ private object Resolve(string makeService, Type makeServiceType, bool isFromMake } else { - buildInstance = TriggerOnResolving(bindData, bindData.ExecResolvingDecorator(buildInstance)); + buildInstance = TriggerOnResolving(bindData, bindData.TriggerResolving(buildInstance)); } return buildInstance; diff --git a/src/CatLib.Core/Support/Events/EventMethod.cs b/src/CatLib.Core/Support/Events/EventMethod.cs index 99a06f6..3150016 100644 --- a/src/CatLib.Core/Support/Events/EventMethod.cs +++ b/src/CatLib.Core/Support/Events/EventMethod.cs @@ -39,7 +39,7 @@ internal sealed class EventMethod /// 依赖注入容器 /// 调用源 /// 调用方法名 - internal EventMethod(IContainer container, object target, string method) + public EventMethod(IContainer container, object target, string method) { this.container = container; this.target = target; From 1e010be44510efe8941cc083c945b7624af82ecb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Sat, 2 Dec 2017 20:13:00 +0800 Subject: [PATCH 15/91] container reslove process update(undone) --- .../Support/Container/Container.cs | 52 ++++++++++++++++--- 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 3c296a0..0120f64 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -988,7 +988,14 @@ protected string GetParamNeedsService(ParameterInfo baseParam, ref InjectAttribu /// 解决结果 protected object ResolveAttrPrimitive(Bindable makeServiceBindData, string service, PropertyInfo baseParam) where T : class, IBindable { - return Make(makeServiceBindData.GetContextual(service)); + var result = SpeculationServiceByParamName(makeServiceBindData, baseParam.Name); + + if(result != null) + { + return result; + } + + throw MakeUnresolvablePrimitiveException(baseParam.Name, baseParam.DeclaringType); } /// @@ -1012,18 +1019,20 @@ protected object ResloveAttrClass(Bindable makeServiceBindData, string ser /// 解决结果 protected object ResolvePrimitive(Bindable makeServiceBindData, string service , ParameterInfo baseParam) where T : class, IBindable { - var newServiceBind = GetBind(makeServiceBindData.GetContextual("@" + baseParam.Name)); - if (newServiceBind != null) + var result = SpeculationServiceByParamName(makeServiceBindData, baseParam.Name); + + if(result != null) { - return Make(newServiceBind.Service); + return result; } - if (baseParam.DefaultValue != DBNull.Value) + if (baseParam.IsOptional + && baseParam.DefaultValue != DBNull.Value) { return baseParam.DefaultValue; } - return Make(makeServiceBindData.GetContextual(service)); + throw MakeUnresolvablePrimitiveException(baseParam.Name, baseParam.Member.DeclaringType); } /// @@ -1035,9 +1044,28 @@ protected object ResolvePrimitive(Bindable makeServiceBindData, string ser /// 解决结果 protected object ResloveClass(Bindable makeServiceBindData, string service, ParameterInfo baseParam) where T : class, IBindable { + // 如果是可选的且是绑定解决异常那么我们就使用默认值 + // baseParam.IsOptional return Make(makeServiceBindData.GetContextual(service)); } + /// + /// 根据参数名字来推测服务 + /// + /// + /// 请求注入操作的服务绑定数据 + /// 参数名 + /// 推测的服务 + protected object SpeculationServiceByParamName(Bindable makeServiceBindData, string paramName) where T : class, IBindable + { + var newServiceBind = GetBind(makeServiceBindData.GetContextual("@" + paramName)); + if (newServiceBind != null) + { + return Make(newServiceBind.Service); + } + return null; + } + /// /// 触发全局解决修饰器 /// @@ -1094,6 +1122,18 @@ protected RuntimeException MakeBuildFaildException(Type makeServiceType, Excepti return new RuntimeException(message, innerException); } + /// + /// 生成一个未能解决基本类型的异常 + /// + /// 变量名 + /// 变量所属类 + /// 运行时异常 + protected RuntimeException MakeUnresolvablePrimitiveException(string name, Type declaringClass) + { + var message = "Unresolvable dependency , resolving [" + name + "] in class [" + declaringClass + "]"; + return new RuntimeException(message); + } + /// /// 标准化服务名 /// From cf6c1046431566bb3d22baea874b3c10b3b8b5b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Sat, 2 Dec 2017 21:13:23 +0800 Subject: [PATCH 16/91] add exception --- .../Support/Container/Container.cs | 4 +- .../Container/UnresolvableException.cs | 46 +++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 src/CatLib.Core/Support/Container/UnresolvableException.cs diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 0120f64..fd422d4 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -1111,7 +1111,7 @@ protected BindData MakeEmptyBindData(string service) /// 构造的服务类型 /// 内部异常 /// 运行时异常 - protected RuntimeException MakeBuildFaildException(Type makeServiceType, Exception innerException) + protected UnresolvableException MakeBuildFaildException(Type makeServiceType, Exception innerException) { var message = "Target [" + makeServiceType + "] build faild."; if (buildStack.Count > 0) @@ -1119,7 +1119,7 @@ protected RuntimeException MakeBuildFaildException(Type makeServiceType, Excepti var previous = string.Join(", ", buildStack.ToArray()); message = "Target [" + makeServiceType + "] build faild while building [" + previous + "]."; } - return new RuntimeException(message, innerException); + return new UnresolvableException(message, innerException); } /// diff --git a/src/CatLib.Core/Support/Container/UnresolvableException.cs b/src/CatLib.Core/Support/Container/UnresolvableException.cs new file mode 100644 index 0000000..9061a09 --- /dev/null +++ b/src/CatLib.Core/Support/Container/UnresolvableException.cs @@ -0,0 +1,46 @@ +/* + * 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 +{ + /// + /// 未能解决异常 + /// + public class UnresolvableException : RuntimeException + { + /// + /// 未能解决异常 + /// + public UnresolvableException() : base() + { + + } + + /// + /// 未能解决异常 + /// + /// 异常消息 + public UnresolvableException(string message) : base(message) + { + } + + /// + /// 未能解决异常 + /// + /// 异常消息 + /// 内部异常 + public UnresolvableException(string message, Exception innerException) : base(message, innerException) + { + } + } +} From ac2af7288b59cad9e91d05120884a836104ba528 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Sat, 2 Dec 2017 22:54:35 +0800 Subject: [PATCH 17/91] container update(undone) --- .../CatLib.Core.NetStandard.csproj | 2 + .../Support/Container/ContainerTests.cs | 15 +- src/CatLib.Core/CatLib.Core.csproj | 1 + .../Support/Container/Container.cs | 143 ++++++++++++++---- 4 files changed, 124 insertions(+), 37 deletions(-) diff --git a/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj b/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj index b091d94..2ee4a13 100644 --- a/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj +++ b/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj @@ -78,6 +78,7 @@ + @@ -127,6 +128,7 @@ + diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs index fe6dd5d..b5c2dce 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs @@ -606,8 +606,9 @@ public void CheckIllegalCallMethod() public void TestContainerCallWithNullParams() { var container = MakeContainer(); + container.Instance("@num", 777); var result = container.Call(this, "TestContainerCall", null); - Assert.AreEqual(0, result); + Assert.AreEqual(777, result); } /// @@ -744,9 +745,10 @@ public void MakeNoClassAttrInject() { var container = MakeContainer(); container.Bind(); + container.Bind("@Time", (c, p) => 100, false); var result = container.Make(); - Assert.AreEqual(0, result.Time); + Assert.AreEqual(100, result.Time); } /// @@ -799,8 +801,9 @@ public void MakeNotClassConstructor() var container = MakeContainer(); container.Bind(); container.Bind(); + container.Instance("@i", 77); var result = container.Make(); - Assert.AreEqual(0, result.I); + Assert.AreEqual(77, result.I); Assert.AreNotEqual(null, result.Dependency); var result2 = container.MakeWith(100); @@ -1454,14 +1457,16 @@ public void TestBaseStructChange() public void TestBaseStructChangeInvalid() { var container = new Container(); - Assert.AreEqual(0, container.Call(this, "TestContainerCall", "100000000000000000000")); + container.Instance(10000); + Assert.AreEqual(10000, container.Call(this, "TestContainerCall", "100000000000000000000")); } [TestMethod] public void TestFormatException() { var container = new Container(); - Assert.AreEqual(0, container.Call(this, "TestContainerCall", new ContainerTest())); + container.Instance("@num", 10); + Assert.AreEqual(10, container.Call(this, "TestContainerCall", new ContainerTest())); } internal class TestNoConstructorAccessClass diff --git a/src/CatLib.Core/CatLib.Core.csproj b/src/CatLib.Core/CatLib.Core.csproj index f3595e0..7399e3e 100644 --- a/src/CatLib.Core/CatLib.Core.csproj +++ b/src/CatLib.Core/CatLib.Core.csproj @@ -50,6 +50,7 @@ + diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index fd422d4..705d380 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -61,6 +61,11 @@ public class Container : IContainer /// private readonly SortSet, int> findType; + /// + /// 类型查询回调缓存 + /// + private readonly Dictionary findTypeCache; + /// /// 方法容器 /// @@ -89,19 +94,22 @@ public class Container : IContainer /// /// 构造一个容器 /// - public Container() + /// 初始预计服务数量 + public Container(int prime = 32) { - tags = new Dictionary>(); - aliases = new Dictionary(); - aliasesReverse = new Dictionary>(); - instances = new Dictionary(); - binds = new Dictionary(); - resolving = new List>(); - release = new List>(); + prime = Math.Max(8, prime); + tags = new Dictionary>((int)(prime * 0.25)); + aliases = new Dictionary(prime * 4); + aliasesReverse = new Dictionary>(prime * 4); + instances = new Dictionary(prime * 4); + binds = new Dictionary(prime * 4); + resolving = new List>((int)(prime * 0.25)); + release = new List>((int)(prime * 0.25)); findType = new SortSet, int>(); + findTypeCache = new Dictionary(prime * 4); injectTarget = typeof(InjectAttribute); - buildStack = new Stack(); - userParamsStack = new Stack(); + buildStack = new Stack(32); + userParamsStack = new Stack(32); methodContainer = new MethodContainer(this); } @@ -191,6 +199,38 @@ public bool HasBind(string service) return GetBind(service) != null; } + /// + /// 是否拥有服务 + /// + /// 服务名或者别名 + /// 是否拥有服务 + public bool HasService(string service) + { + Guard.NotEmptyOrNull(service, "service"); + lock (syncRoot) + { + service = NormalizeService(service); + service = AliasToService(service); + return HasBind(service) || HasInstance(service) || GetServiceType(service) != null; + } + } + + /// + /// 是否已经静态化 + /// + /// 服务名或别名 + /// 是否已经静态化 + public bool HasInstance(string service) + { + Guard.NotEmptyOrNull(service, "service"); + lock (syncRoot) + { + service = NormalizeService(service); + service = AliasToService(service); + return instances.ContainsKey(service); + } + } + /// /// 服务是否是静态化的,如果服务不存在也将返回false /// @@ -775,7 +815,7 @@ protected object Build(BindData makeServiceBindData, Type makeServiceType, objec } catch (Exception ex) { - throw MakeBuildFaildException(makeServiceType, ex); + throw MakeBuildFaildException(makeServiceBindData.Service, makeServiceType, ex); } } @@ -792,7 +832,7 @@ protected object Build(BindData makeServiceBindData, Type makeServiceType, objec } catch (Exception ex) { - throw MakeBuildFaildException(makeServiceType, ex); + throw MakeBuildFaildException(makeServiceBindData.Service, makeServiceType, ex); } } @@ -988,8 +1028,13 @@ protected string GetParamNeedsService(ParameterInfo baseParam, ref InjectAttribu /// 解决结果 protected object ResolveAttrPrimitive(Bindable makeServiceBindData, string service, PropertyInfo baseParam) where T : class, IBindable { - var result = SpeculationServiceByParamName(makeServiceBindData, baseParam.Name); + service = makeServiceBindData.GetContextual(service); + if (HasService(service)) + { + return Make(service); + } + var result = SpeculationServiceByParamName(makeServiceBindData, baseParam.Name); if(result != null) { return result; @@ -1019,17 +1064,21 @@ protected object ResloveAttrClass(Bindable makeServiceBindData, string ser /// 解决结果 protected object ResolvePrimitive(Bindable makeServiceBindData, string service , ParameterInfo baseParam) where T : class, IBindable { - var result = SpeculationServiceByParamName(makeServiceBindData, baseParam.Name); + service = makeServiceBindData.GetContextual(service); + if (HasService(service)) + { + return Make(service); + } + var result = SpeculationServiceByParamName(makeServiceBindData, baseParam.Name); if(result != null) { return result; } - if (baseParam.IsOptional - && baseParam.DefaultValue != DBNull.Value) + if (baseParam.IsOptional) { - return baseParam.DefaultValue; + return baseParam.DefaultValue != DBNull.Value ? baseParam.DefaultValue : null; } throw MakeUnresolvablePrimitiveException(baseParam.Name, baseParam.Member.DeclaringType); @@ -1044,9 +1093,18 @@ protected object ResolvePrimitive(Bindable makeServiceBindData, string ser /// 解决结果 protected object ResloveClass(Bindable makeServiceBindData, string service, ParameterInfo baseParam) where T : class, IBindable { - // 如果是可选的且是绑定解决异常那么我们就使用默认值 - // baseParam.IsOptional - return Make(makeServiceBindData.GetContextual(service)); + try + { + return Make(makeServiceBindData.GetContextual(service)); + } + catch (UnresolvableException ex) + { + if (baseParam.IsOptional) + { + return baseParam.DefaultValue != DBNull.Value ? baseParam.DefaultValue : null; + } + throw ex; + } } /// @@ -1058,12 +1116,8 @@ protected object ResloveClass(Bindable makeServiceBindData, string service /// 推测的服务 protected object SpeculationServiceByParamName(Bindable makeServiceBindData, string paramName) where T : class, IBindable { - var newServiceBind = GetBind(makeServiceBindData.GetContextual("@" + paramName)); - if (newServiceBind != null) - { - return Make(newServiceBind.Service); - } - return null; + var service = makeServiceBindData.GetContextual("@" + paramName); + return HasService(service) ? Make(service) : null; } /// @@ -1108,16 +1162,17 @@ protected BindData MakeEmptyBindData(string service) /// /// 生成一个编译失败异常 /// + /// 构造的服务名字 /// 构造的服务类型 /// 内部异常 /// 运行时异常 - protected UnresolvableException MakeBuildFaildException(Type makeServiceType, Exception innerException) + protected UnresolvableException MakeBuildFaildException(string makeService, Type makeServiceType, Exception innerException) { - var message = "Target [" + makeServiceType + "] build faild."; + var message = "Target [" +(makeServiceType != null ? makeServiceType.ToString() : "NULL") + "] build faild. Service [" + makeService + "]"; if (buildStack.Count > 0) { var previous = string.Join(", ", buildStack.ToArray()); - message = "Target [" + makeServiceType + "] build faild while building [" + previous + "]."; + message = "Target [" + (makeServiceType != null ? makeServiceType.ToString() : "NULL") + "] build faild. Service [" + makeService + "] . While building [" + previous + "]."; } return new UnresolvableException(message, innerException); } @@ -1178,6 +1233,20 @@ protected void GuardUserParamsCount(int count) } } + /// + /// 守卫解决实例状态 + /// + /// 服务实例 + /// 服务名 + /// 服务类型 + protected void GuardResolveInstance(object instance,string makeService, Type makeServiceType) + { + if (instance == null) + { + throw MakeBuildFaildException(makeService, makeServiceType, null); + } + } + /// /// 获取通过服务名获取服务的类型 /// @@ -1185,15 +1254,23 @@ protected void GuardUserParamsCount(int count) /// 服务类型 protected Type GetServiceType(string service) { + Type result; + + if (findTypeCache.TryGetValue(service, out result)) + { + return result; + } + foreach (var finder in findType) { var type = finder.Invoke(service); if (type != null) { - return type; + return findTypeCache[service] = type; } } - return null; + + return findTypeCache[service] = null; } /// @@ -1208,7 +1285,9 @@ private object Resolve(string makeService, Type makeServiceType, bool isFromMake { var bindData = GetBindFillable(makeService); var buildInstance = isFromMake ? BuildUseConcrete(bindData, makeServiceType, userParams) - : Build(bindData, makeServiceType ?? GetServiceType(bindData.Service), userParams); + : Build(bindData, makeServiceType ?? (makeServiceType = GetServiceType(bindData.Service)), userParams); + + GuardResolveInstance(buildInstance, makeService, makeServiceType); //只有是来自于make函数的调用时才执行di,包装,以及修饰 if (!isFromMake) From 72ffadd9bc58d14b37800c2615403eb1a0d3610d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Sun, 3 Dec 2017 09:18:36 +0800 Subject: [PATCH 18/91] container optimization --- .../Support/Container/BindDataTests.cs | 6 +- .../Support/Container/ContainerHelperTests.cs | 7 ++- .../Support/Container/ContainerTests.cs | 39 +++++++++---- .../Support/Container/Container.cs | 55 +++++++------------ .../Support/Container/InjectAttribute.cs | 6 -- 5 files changed, 60 insertions(+), 53 deletions(-) diff --git a/src/CatLib.Core.Tests/Support/Container/BindDataTests.cs b/src/CatLib.Core.Tests/Support/Container/BindDataTests.cs index 0d1a115..fb0f170 100644 --- a/src/CatLib.Core.Tests/Support/Container/BindDataTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/BindDataTests.cs @@ -206,7 +206,11 @@ public void CanUnBind() Assert.AreEqual("hello world", container.Make("CanUnBind").ToString()); bindData.UnBind(); - Assert.AreEqual(null, container.Make("CanUnBind")); + + ExceptionAssert.Throws(() => + { + container.Make("CanUnBind"); + }); } /// diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerHelperTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerHelperTests.cs index 8439fce..f56a848 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerHelperTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerHelperTests.cs @@ -9,6 +9,7 @@ * Document: http://catlib.io/ */ +using System; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace CatLib.Tests @@ -110,11 +111,15 @@ public void TestRelease() var container = MakeContainer(); var obj = new TestClassService(); container.Instance(obj); + container.OnFindType((str) => + { + return Type.GetType(str); + }); Assert.AreSame(obj, container.Make()); container.Release(); // 因为被释放后容器会容器会自动推测出所需类的实例 - Assert.AreNotSame(obj, container.Make()); + Assert.AreSame(obj.GetType(), container.Make().GetType()); } /// diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs index b5c2dce..e74f03e 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs @@ -108,7 +108,12 @@ public void MergeTag() container.Tag("hello", "world"); container.Tag("hello", "world2"); + container.Bind("world", (c, p) => "hello"); + container.Bind("world2", (c, p) => "world"); + Assert.AreEqual(2, container.Tagged("hello").Length); + Assert.AreEqual("hello", container.Tagged("hello")[0]); + Assert.AreEqual("world", container.Tagged("hello")[1]); } /// @@ -677,13 +682,13 @@ public class MakeTestClass [Inject] public MakeTestClassDependency Dependency { get; set; } - [Inject(Required = true)] + [Inject] public MakeTestClassDependency DependencyRequired { get; set; } [Inject("AliasName")] public MakeTestClassDependency2 DependencyAlias { get; set; } - [Inject("AliasNameRequired", Required = true)] + [Inject("AliasNameRequired")] public MakeTestClassDependency DependencyAliasRequired { get; set; } public MakeTestClass(MakeTestClassDependency dependency) @@ -766,6 +771,7 @@ public void MakeNoBindType() }); container.Bind().Alias("AliasNameRequired"); + container.Bind().Alias("AliasName"); var result = container.Make(); Assert.AreNotEqual(null, result); @@ -820,6 +826,7 @@ public void CanMake() var container = MakeContainer(); container.Bind(); container.Bind().Alias("AliasNameRequired"); + container.Bind().Alias("AliasName"); var result = container.Make(); Assert.AreEqual(typeof(MakeTestClass), result.GetType()); @@ -894,6 +901,7 @@ public void CanMakeNormalBind() var container = MakeContainer(); container.Bind(); container.Bind().Alias("AliasNameRequired"); + container.Bind().Alias("AliasName"); var result1 = container.Make(); var result2 = container.Make(); @@ -902,7 +910,7 @@ public void CanMakeNormalBind() Assert.AreNotSame(result1.Dependency, result1.DependencyRequired); Assert.AreNotSame(null, result1.DependencyRequired); Assert.AreNotSame(null, result1.DependencyAliasRequired); - Assert.AreSame(null, result1.DependencyAlias); + Assert.AreNotEqual(null, result1.DependencyAlias); } /// @@ -1023,7 +1031,7 @@ public class TestMakeParamInjectAttrRequiredClass { private IMsg msg; public TestMakeParamInjectAttrRequiredClass( - [Inject(Required = true)]IMsg msg) + IMsg msg) { this.msg = msg; } @@ -1121,9 +1129,9 @@ public void CanMakeGenericInject() Assert.AreNotEqual(null, result.Cls); Assert.AreEqual(typeof(string).ToString(), result.Cls.GetMsg()); - container.Bind>((app, param) => null); + container.Bind>((app, param) => new GenericClass()); result = container.Make(); - Assert.AreEqual(null, result.Cls); + Assert.AreNotEqual(null, result.Cls); } @@ -1193,8 +1201,11 @@ public void InvalidClassNew() { return Type.GetType(str); }); - var result = container.Make(); - Assert.AreEqual(null, result); + + ExceptionAssert.Throws(() => + { + container.Make(); + }); } /// @@ -1415,8 +1426,16 @@ public void TestReleaseAllStaticService() container.Flush(); Assert.AreEqual(true, isCallTest); - Assert.AreEqual(null, container.Make("TestInstance2")); - Assert.AreEqual(null, container.Make("Test")); + + ExceptionAssert.Throws(() => + { + container.Make("TestInstance2"); + }); + + ExceptionAssert.Throws(() => + { + container.Make("Test"); + }); } [TestMethod] diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 705d380..55a2386 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -858,8 +858,7 @@ protected void AttributeInject(Bindable makeServiceBindData, object makeSe continue; } - InjectAttribute injectAttr = null; - var needService = GetPropertyNeedsService(property, ref injectAttr); + var needService = GetPropertyNeedsService(property); object instance; if (property.PropertyType.IsClass @@ -872,14 +871,9 @@ protected void AttributeInject(Bindable makeServiceBindData, object makeSe instance = ResolveAttrPrimitive(makeServiceBindData, needService, property); } - if (!CheckInjectAttrRequired(injectAttr, instance)) - { - throw new RuntimeException("[" + makeServiceBindData.Service + "] Attr [" + property.PropertyType + "] Required [" + needService + "] Service."); - } - if (!CheckInstanceIsInstanceOfType(property.PropertyType, instance)) { - throw new RuntimeException("[" + makeServiceBindData.Service + "] Attr inject type must be [" + property.PropertyType + "] , But instance is [" + instance.GetType() + "] , Make service is [" + needService + "]."); + throw new UnresolvableException("[" + makeServiceBindData.Service + "] Attr inject type must be [" + property.PropertyType + "] , But instance is [" + instance.GetType() + "] , Make service is [" + needService + "]."); } property.SetValue(makeServiceInstance, instance, null); @@ -907,8 +901,7 @@ protected object[] GetDependencies(Bindable makeServiceBindData, IList(Bindable makeServiceBindData, IList /// 字段 - /// 依赖注入标记 /// 需求的服务名 - protected string GetPropertyNeedsService(PropertyInfo property, ref InjectAttribute injectAttr) + protected string GetPropertyNeedsService(PropertyInfo property) { - injectAttr = (InjectAttribute)property.GetCustomAttributes(injectTarget, false)[0]; + var injectAttr = (InjectAttribute)property.GetCustomAttributes(injectTarget, false)[0]; return string.IsNullOrEmpty(injectAttr.Alias) ? Type2Service(property.PropertyType) : injectAttr.Alias; @@ -999,9 +986,8 @@ protected string GetPropertyNeedsService(PropertyInfo property, ref InjectAttrib /// 获取参数需求服务 /// /// 当前正在解决的变量 - /// 依赖注入标记 /// 需求的服务名 - protected string GetParamNeedsService(ParameterInfo baseParam, ref InjectAttribute injectAttr) + protected string GetParamNeedsService(ParameterInfo baseParam) { var needService = Type2Service(baseParam.ParameterType); if (baseParam.IsDefined(injectTarget, false)) @@ -1009,7 +995,7 @@ protected string GetParamNeedsService(ParameterInfo baseParam, ref InjectAttribu var propertyAttrs = baseParam.GetCustomAttributes(injectTarget, false); if (propertyAttrs.Length > 0) { - injectAttr = (InjectAttribute)propertyAttrs[0]; + var injectAttr = (InjectAttribute)propertyAttrs[0]; if (!string.IsNullOrEmpty(injectAttr.Alias)) { needService = injectAttr.Alias; @@ -1168,12 +1154,22 @@ protected BindData MakeEmptyBindData(string service) /// 运行时异常 protected UnresolvableException MakeBuildFaildException(string makeService, Type makeServiceType, Exception innerException) { - var message = "Target [" +(makeServiceType != null ? makeServiceType.ToString() : "NULL") + "] build faild. Service [" + makeService + "]"; + string message; + if (makeServiceType != null) + { + message = "Target [" + makeServiceType + "] build faild. Service is [" + makeService + "]"; + } + else + { + message = "Service [" + makeService + "] is not exists."; + } + if (buildStack.Count > 0) { var previous = string.Join(", ", buildStack.ToArray()); - message = "Target [" + (makeServiceType != null ? makeServiceType.ToString() : "NULL") + "] build faild. Service [" + makeService + "] . While building [" + previous + "]."; + message += " While building [" + previous + "]."; } + return new UnresolvableException(message, innerException); } @@ -1210,17 +1206,6 @@ protected bool CheckInstanceIsInstanceOfType(Type type, object instance) return instance == null || type.IsInstanceOfType(instance); } - /// - /// 检查依赖注入的必须标记 - /// - /// 依赖注入标记 - /// 生成的实例 - /// 是否通过检查 - protected bool CheckInjectAttrRequired(InjectAttribute injectAttr, object instance) - { - return injectAttr == null || !injectAttr.Required || instance != null; - } - /// /// 保证用户传入参数必须小于指定值 /// diff --git a/src/CatLib.Core/Support/Container/InjectAttribute.cs b/src/CatLib.Core/Support/Container/InjectAttribute.cs index 88cb3a8..a62e0e4 100644 --- a/src/CatLib.Core/Support/Container/InjectAttribute.cs +++ b/src/CatLib.Core/Support/Container/InjectAttribute.cs @@ -26,12 +26,6 @@ public class InjectAttribute : Attribute /// public string Alias { get; private set; } - /// - /// 是否是必须的 - /// 如果约束为必须当依赖注入失败时则会引发一个异常 - /// - public bool Required { get; set; } - /// /// 声明注入 /// From 63db3e8e353e9588ff4605cc815783120a2b9956 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Sun, 3 Dec 2017 11:24:39 +0800 Subject: [PATCH 19/91] container optimization --- .../Support/Container/ContainerTests.cs | 115 ++++++ .../Support/Container/Container.cs | 367 +++++++++--------- .../Support/Container/IContainer.cs | 7 + 3 files changed, 304 insertions(+), 185 deletions(-) diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs index e74f03e..3b11dd6 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs @@ -1023,6 +1023,121 @@ public void CanParamUseInjectAttr() Assert.AreEqual("hello", cls.GetMsg()); } + public class TestMakeBasePrimitive + { + [Inject] + public int Value { get; set; } + } + + [TestMethod] + public void TestUnresolvablePrimitiveAttr() + { + var container = MakeContainer(); + container.Bind(); + + ExceptionAssert.Throws(() => + { + container.Make(); + }); + } + + public class TestMakeBasePrimitiveConstructor + { + public TestMakeBasePrimitiveConstructor(int value) + { + + } + } + + [TestMethod] + public void TestUnresolvablePrimitiveConstructor() + { + var container = MakeContainer(); + container.Bind(); + ExceptionAssert.Throws(() => + { + container.Make(); + }); + } + + public class TestOptionalPrimitiveClass + { + public TestOptionalPrimitiveClass(int value = 100) + { + Assert.AreEqual(100, value); + } + } + + public class SupportNullContainer : Container + { + protected override void GuardResolveInstance(object instance, string makeService, Type makeServiceType) + { + + } + } + + [TestMethod] + public void TestSupportNullValueContainer() + { + var container = new SupportNullContainer() as IContainer; + container.Bind("null", (c, p) => null); + + Assert.AreEqual(null, container.Make("null")); + } + + public class TestInjectNullClass + { + public TestInjectNullClass(TestMakeBasePrimitiveConstructor cls) + { + Assert.AreEqual(null, cls); + } + } + + [TestMethod] + public void TestInjectNull() + { + var container = new SupportNullContainer() as IContainer; + container.Bind(); + + container.Make(); + } + + public class TestDefaultValueClass + { + public TestDefaultValueClass(SupportNullContainer container = null) + { + Assert.AreEqual(null, container); + } + } + + [TestMethod] + public void TestDefaultValue() + { + var container = new Container(); + container.Bind(); + container.Make(); + } + + [TestMethod] + public void TestAllFalseFindType() + { + var container = new Container(); + + container.OnFindType((str) => null); + + ExceptionAssert.Throws(() => + { + container.Make(); + }); + } + + [TestMethod] + public void TestOptionalPrimitive() + { + var container = MakeContainer(); + container.Bind(); + container.Make(); + } /// /// 参数注入是必须的 diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 55a2386..1970a4d 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -200,34 +200,34 @@ public bool HasBind(string service) } /// - /// 是否拥有服务 + /// 是否已经实例静态化 /// - /// 服务名或者别名 - /// 是否拥有服务 - public bool HasService(string service) + /// 服务名或别名 + /// 是否已经静态化 + public bool HasInstance(string service) { Guard.NotEmptyOrNull(service, "service"); lock (syncRoot) { service = NormalizeService(service); service = AliasToService(service); - return HasBind(service) || HasInstance(service) || GetServiceType(service) != null; + return instances.ContainsKey(service); } } /// - /// 是否已经静态化 + /// 是否可以生成服务 /// - /// 服务名或别名 - /// 是否已经静态化 - public bool HasInstance(string service) + /// 服务名或者别名 + /// 是否可以生成服务 + public bool CanMake(string service) { Guard.NotEmptyOrNull(service, "service"); lock (syncRoot) { service = NormalizeService(service); service = AliasToService(service); - return instances.ContainsKey(service); + return HasBind(service) || HasInstance(service) || GetServiceType(service) != null; } } @@ -692,6 +692,7 @@ public void Flush() resolving.Clear(); release.Clear(); findType.Clear(); + findTypeCache.Clear(); } } @@ -788,149 +789,13 @@ public void UnBind(string service) } } - /// - /// 构造服务实现 - /// - /// 服务绑定数据 - /// 服务类型 - /// 用户传入的构造参数 - /// 服务实例 - protected object Build(BindData makeServiceBindData, Type makeServiceType, object[] userParams) - { - userParams = userParams ?? new object[] { }; - - if (makeServiceType == null - || makeServiceType.IsAbstract - || makeServiceType.IsInterface) - { - return null; - } - - var constructor = makeServiceType.GetConstructors(); - if (constructor.Length <= 0) - { - try - { - return Activator.CreateInstance(makeServiceType); - } - catch (Exception ex) - { - throw MakeBuildFaildException(makeServiceBindData.Service, makeServiceType, ex); - } - } - - var parameter = new List(constructor[constructor.Length - 1].GetParameters()); - - if (parameter.Count > 0) - { - userParams = GetDependencies(makeServiceBindData, parameter, userParams); - } - - try - { - return Activator.CreateInstance(makeServiceType, userParams); - } - catch (Exception ex) - { - throw MakeBuildFaildException(makeServiceBindData.Service, makeServiceType, ex); - } - } - - /// - /// 属性注入 - /// - /// 服务绑定数据 - /// 服务实例 - /// 服务实例 - /// 属性是必须的或者注入类型和需求类型不一致 - protected void AttributeInject(Bindable makeServiceBindData, object makeServiceInstance) where T : class , IBindable - { - if (makeServiceInstance == null) - { - return; - } - - foreach (var property in makeServiceInstance.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)) - { - if (!property.CanWrite - || !property.IsDefined(injectTarget, false)) - { - continue; - } - - var needService = GetPropertyNeedsService(property); - - object instance; - if (property.PropertyType.IsClass - || property.PropertyType.IsInterface) - { - instance = ResloveAttrClass(makeServiceBindData, needService, property); - } - else - { - instance = ResolveAttrPrimitive(makeServiceBindData, needService, property); - } - - if (!CheckInstanceIsInstanceOfType(property.PropertyType, instance)) - { - throw new UnresolvableException("[" + makeServiceBindData.Service + "] Attr inject type must be [" + property.PropertyType + "] , But instance is [" + instance.GetType() + "] , Make service is [" + needService + "]."); - } - - property.SetValue(makeServiceInstance, instance, null); - } - } - - /// - /// 获取依赖解决结果 - /// - /// 服务绑定数据 - /// 服务实例的参数信息 - /// 输入的构造参数列表 - /// 服务所需参数的解决结果 - /// 生成的实例类型和需求类型不一致 - protected object[] GetDependencies(Bindable makeServiceBindData, IList baseParams, object[] userParams) where T : class, IBindable - { - var results = new List(); - - foreach (var baseParam in baseParams) - { - var instance = GetDependenciesFromUserParams(baseParam, ref userParams); - if (instance != null) - { - results.Add(instance); - continue; - } - - var needService = GetParamNeedsService(baseParam); - - if (baseParam.ParameterType.IsClass - || baseParam.ParameterType.IsInterface) - { - instance = ResloveClass(makeServiceBindData, needService, baseParam); - } - else - { - instance = ResolvePrimitive(makeServiceBindData, needService, baseParam); - } - - if (!CheckInstanceIsInstanceOfType(baseParam.ParameterType, instance)) - { - throw new UnresolvableException("[" + makeServiceBindData.Service + "] Params inject type must be [" + baseParam.ParameterType + "] , But instance is [" + instance.GetType() + "] Make service is [" + needService + "]."); - } - - results.Add(instance); - } - - return results.ToArray(); - } - /// /// 从用户传入的参数中获取依赖 /// /// 基础参数 /// 用户传入参数 /// 合适的注入参数 - protected object GetDependenciesFromUserParams(ParameterInfo baseParam, ref object[] userParams) + protected virtual object GetDependenciesFromUserParams(ParameterInfo baseParam, ref object[] userParams) { if (userParams == null) { @@ -958,11 +823,6 @@ protected object GetDependenciesFromUserParams(ParameterInfo baseParam, ref obje } catch (Exception) { - /* - throw new RuntimeException( - string.Format("Params [{0}({1})] can not convert to [{2}] , Service [{3}]", - baseParam.Name, userParam, baseParam.ParameterType, service - ), ex);*/ } } @@ -974,7 +834,7 @@ protected object GetDependenciesFromUserParams(ParameterInfo baseParam, ref obje /// /// 字段 /// 需求的服务名 - protected string GetPropertyNeedsService(PropertyInfo property) + protected virtual string GetPropertyNeedsService(PropertyInfo property) { var injectAttr = (InjectAttribute)property.GetCustomAttributes(injectTarget, false)[0]; return string.IsNullOrEmpty(injectAttr.Alias) @@ -987,7 +847,7 @@ protected string GetPropertyNeedsService(PropertyInfo property) /// /// 当前正在解决的变量 /// 需求的服务名 - protected string GetParamNeedsService(ParameterInfo baseParam) + protected virtual string GetParamNeedsService(ParameterInfo baseParam) { var needService = Type2Service(baseParam.ParameterType); if (baseParam.IsDefined(injectTarget, false)) @@ -1012,10 +872,10 @@ protected string GetParamNeedsService(ParameterInfo baseParam) /// 希望解决的服务名或者别名 /// 当前正在解决的变量 /// 解决结果 - protected object ResolveAttrPrimitive(Bindable makeServiceBindData, string service, PropertyInfo baseParam) where T : class, IBindable + protected virtual object ResolveAttrPrimitive(Bindable makeServiceBindData, string service, PropertyInfo baseParam) where T : class, IBindable { service = makeServiceBindData.GetContextual(service); - if (HasService(service)) + if (CanMake(service)) { return Make(service); } @@ -1036,7 +896,7 @@ protected object ResolveAttrPrimitive(Bindable makeServiceBindData, string /// 希望解决的服务名或者别名 /// 当前正在解决的变量 /// 解决结果 - protected object ResloveAttrClass(Bindable makeServiceBindData, string service, PropertyInfo baseParam) where T : class, IBindable + protected virtual object ResloveAttrClass(Bindable makeServiceBindData, string service, PropertyInfo baseParam) where T : class, IBindable { return Make(makeServiceBindData.GetContextual(service)); } @@ -1048,10 +908,10 @@ protected object ResloveAttrClass(Bindable makeServiceBindData, string ser /// 希望解决的服务名或者别名 /// 当前正在解决的变量 /// 解决结果 - protected object ResolvePrimitive(Bindable makeServiceBindData, string service , ParameterInfo baseParam) where T : class, IBindable + protected virtual object ResolvePrimitive(Bindable makeServiceBindData, string service , ParameterInfo baseParam) where T : class, IBindable { service = makeServiceBindData.GetContextual(service); - if (HasService(service)) + if (CanMake(service)) { return Make(service); } @@ -1064,7 +924,7 @@ protected object ResolvePrimitive(Bindable makeServiceBindData, string ser if (baseParam.IsOptional) { - return baseParam.DefaultValue != DBNull.Value ? baseParam.DefaultValue : null; + return baseParam.DefaultValue; } throw MakeUnresolvablePrimitiveException(baseParam.Name, baseParam.Member.DeclaringType); @@ -1077,7 +937,7 @@ protected object ResolvePrimitive(Bindable makeServiceBindData, string ser /// 希望解决的服务名或者别名 /// 当前正在解决的变量 /// 解决结果 - protected object ResloveClass(Bindable makeServiceBindData, string service, ParameterInfo baseParam) where T : class, IBindable + protected virtual object ResloveClass(Bindable makeServiceBindData, string service, ParameterInfo baseParam) where T : class, IBindable { try { @@ -1087,7 +947,7 @@ protected object ResloveClass(Bindable makeServiceBindData, string service { if (baseParam.IsOptional) { - return baseParam.DefaultValue != DBNull.Value ? baseParam.DefaultValue : null; + return baseParam.DefaultValue; } throw ex; } @@ -1100,10 +960,10 @@ protected object ResloveClass(Bindable makeServiceBindData, string service /// 请求注入操作的服务绑定数据 /// 参数名 /// 推测的服务 - protected object SpeculationServiceByParamName(Bindable makeServiceBindData, string paramName) where T : class, IBindable + protected virtual object SpeculationServiceByParamName(Bindable makeServiceBindData, string paramName) where T : class, IBindable { var service = makeServiceBindData.GetContextual("@" + paramName); - return HasService(service) ? Make(service) : null; + return CanMake(service) ? Make(service) : null; } /// @@ -1112,7 +972,7 @@ protected object SpeculationServiceByParamName(Bindable makeServiceBindDat /// 服务绑定数据 /// 服务实例 /// 被修饰器修饰后的服务实例 - protected object TriggerOnResolving(IBindData bindData, object obj) + protected virtual object TriggerOnResolving(IBindData bindData, object obj) { foreach (var func in resolving) { @@ -1127,7 +987,7 @@ protected object TriggerOnResolving(IBindData bindData, object obj) /// 服务绑定数据 /// 服务实例 /// 被修饰器修饰后的服务实例 - protected void TriggerOnRelease(IBindData bindData, object obj) + protected virtual void TriggerOnRelease(IBindData bindData, object obj) { foreach (var action in release) { @@ -1135,16 +995,6 @@ protected void TriggerOnRelease(IBindData bindData, object obj) } } - /// - /// 制作一个空的绑定数据 - /// - /// 服务名 - /// 空绑定数据 - protected BindData MakeEmptyBindData(string service) - { - return new BindData(this, service, null, false); - } - /// /// 生成一个编译失败异常 /// @@ -1152,7 +1002,7 @@ protected BindData MakeEmptyBindData(string service) /// 构造的服务类型 /// 内部异常 /// 运行时异常 - protected UnresolvableException MakeBuildFaildException(string makeService, Type makeServiceType, Exception innerException) + protected virtual UnresolvableException MakeBuildFaildException(string makeService, Type makeServiceType, Exception innerException) { string message; if (makeServiceType != null) @@ -1179,10 +1029,10 @@ protected UnresolvableException MakeBuildFaildException(string makeService, Type /// 变量名 /// 变量所属类 /// 运行时异常 - protected RuntimeException MakeUnresolvablePrimitiveException(string name, Type declaringClass) + protected virtual UnresolvableException MakeUnresolvablePrimitiveException(string name, Type declaringClass) { - var message = "Unresolvable dependency , resolving [" + name + "] in class [" + declaringClass + "]"; - return new RuntimeException(message); + var message = "Unresolvable primitive dependency , resolving [" + name + "] in class [" + declaringClass + "]"; + return new UnresolvableException(message); } /// @@ -1190,7 +1040,7 @@ protected RuntimeException MakeUnresolvablePrimitiveException(string name, Type /// /// 服务名 /// 标准化后的服务名 - protected string NormalizeService(string service) + protected virtual string NormalizeService(string service) { return service.Trim(); } @@ -1201,7 +1051,7 @@ protected string NormalizeService(string service) /// 需要实现自的类型 /// 生成的实例 /// 是否符合类型 - protected bool CheckInstanceIsInstanceOfType(Type type, object instance) + protected virtual bool CheckInstanceIsInstanceOfType(Type type, object instance) { return instance == null || type.IsInstanceOfType(instance); } @@ -1210,7 +1060,7 @@ protected bool CheckInstanceIsInstanceOfType(Type type, object instance) /// 保证用户传入参数必须小于指定值 /// /// 传入参数数量 - protected void GuardUserParamsCount(int count) + protected virtual void GuardUserParamsCount(int count) { if (count > 255) { @@ -1224,7 +1074,7 @@ protected void GuardUserParamsCount(int count) /// 服务实例 /// 服务名 /// 服务类型 - protected void GuardResolveInstance(object instance,string makeService, Type makeServiceType) + protected virtual void GuardResolveInstance(object instance,string makeService, Type makeServiceType) { if (instance == null) { @@ -1237,7 +1087,7 @@ protected void GuardResolveInstance(object instance,string makeService, Type mak /// /// 服务名 /// 服务类型 - protected Type GetServiceType(string service) + protected virtual Type GetServiceType(string service) { Type result; @@ -1258,6 +1108,105 @@ protected Type GetServiceType(string service) return findTypeCache[service] = null; } + /// + /// 属性注入 + /// + /// 服务绑定数据 + /// 服务实例 + /// 服务实例 + /// 属性是必须的或者注入类型和需求类型不一致 + protected void AttributeInject(Bindable makeServiceBindData, object makeServiceInstance) where T : class, IBindable + { + if (makeServiceInstance == null) + { + return; + } + + foreach (var property in makeServiceInstance.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)) + { + if (!property.CanWrite + || !property.IsDefined(injectTarget, false)) + { + continue; + } + + var needService = GetPropertyNeedsService(property); + + object instance; + if (property.PropertyType.IsClass + || property.PropertyType.IsInterface) + { + instance = ResloveAttrClass(makeServiceBindData, needService, property); + } + else + { + instance = ResolveAttrPrimitive(makeServiceBindData, needService, property); + } + + if (!CheckInstanceIsInstanceOfType(property.PropertyType, instance)) + { + throw new UnresolvableException("[" + makeServiceBindData.Service + "] Attr inject type must be [" + property.PropertyType + "] , But instance is [" + instance.GetType() + "] , Make service is [" + needService + "]."); + } + + property.SetValue(makeServiceInstance, instance, null); + } + } + + /// + /// 获取依赖解决结果 + /// + /// 服务绑定数据 + /// 服务实例的参数信息 + /// 输入的构造参数列表 + /// 服务所需参数的解决结果 + /// 生成的实例类型和需求类型不一致 + protected object[] GetDependencies(Bindable makeServiceBindData, IList baseParams, object[] userParams) where T : class, IBindable + { + var results = new List(); + + foreach (var baseParam in baseParams) + { + var instance = GetDependenciesFromUserParams(baseParam, ref userParams); + if (instance != null) + { + results.Add(instance); + continue; + } + + var needService = GetParamNeedsService(baseParam); + + if (baseParam.ParameterType.IsClass + || baseParam.ParameterType.IsInterface) + { + instance = ResloveClass(makeServiceBindData, needService, baseParam); + } + else + { + instance = ResolvePrimitive(makeServiceBindData, needService, baseParam); + } + + if (!CheckInstanceIsInstanceOfType(baseParam.ParameterType, instance)) + { + throw new UnresolvableException("[" + makeServiceBindData.Service + "] Params inject type must be [" + baseParam.ParameterType + "] , But instance is [" + instance.GetType() + "] Make service is [" + needService + "]."); + } + + results.Add(instance); + } + + return results.ToArray(); + } + + + /// + /// 制作一个空的绑定数据 + /// + /// 服务名 + /// 空绑定数据 + protected BindData MakeEmptyBindData(string service) + { + return new BindData(this, service, null, false); + } + /// /// 解决服务 /// @@ -1294,6 +1243,54 @@ private object Resolve(string makeService, Type makeServiceType, bool isFromMake return buildInstance; } + /// + /// 构造服务实现 + /// + /// 服务绑定数据 + /// 服务类型 + /// 用户传入的构造参数 + /// 服务实例 + private object Build(BindData makeServiceBindData, Type makeServiceType, object[] userParams) + { + userParams = userParams ?? new object[] { }; + + if (makeServiceType == null + || makeServiceType.IsAbstract + || makeServiceType.IsInterface) + { + return null; + } + + var constructor = makeServiceType.GetConstructors(); + if (constructor.Length <= 0) + { + try + { + return Activator.CreateInstance(makeServiceType); + } + catch (Exception ex) + { + throw MakeBuildFaildException(makeServiceBindData.Service, makeServiceType, ex); + } + } + + var parameter = new List(constructor[constructor.Length - 1].GetParameters()); + + if (parameter.Count > 0) + { + userParams = GetDependencies(makeServiceBindData, parameter, userParams); + } + + try + { + return Activator.CreateInstance(makeServiceType, userParams); + } + catch (Exception ex) + { + throw MakeBuildFaildException(makeServiceBindData.Service, makeServiceType, ex); + } + } + /// /// 常规编译一个服务 /// diff --git a/src/CatLib.Core/Support/Container/IContainer.cs b/src/CatLib.Core/Support/Container/IContainer.cs index 24038ca..96481db 100644 --- a/src/CatLib.Core/Support/Container/IContainer.cs +++ b/src/CatLib.Core/Support/Container/IContainer.cs @@ -33,6 +33,13 @@ public interface IContainer /// 返回一个bool值代表服务是否被绑定 bool HasBind(string service); + /// + /// 是否可以生成服务 + /// + /// 服务名或者别名 + /// 是否可以生成服务 + bool CanMake(string service); + /// /// 服务是否是静态化的,如果服务不存在也将返回false /// From caa9fc64853ddf8cb9988cb5b34e57b52f919909 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Sun, 3 Dec 2017 13:41:48 +0800 Subject: [PATCH 20/91] add dict class --- .../Support/Util/ArrTests.cs | 6 + src/CatLib.Core/Support/Util/Arr.cs | 7 + src/CatLib.Core/Support/Util/Dict.cs | 251 ++++++++++++++++++ 3 files changed, 264 insertions(+) create mode 100644 src/CatLib.Core/Support/Util/Dict.cs diff --git a/src/CatLib.Core.Tests/Support/Util/ArrTests.cs b/src/CatLib.Core.Tests/Support/Util/ArrTests.cs index 8c4b493..60ecd88 100644 --- a/src/CatLib.Core.Tests/Support/Util/ArrTests.cs +++ b/src/CatLib.Core.Tests/Support/Util/ArrTests.cs @@ -456,6 +456,12 @@ public void TestReverse() Assert.AreEqual("a", data[0]); Assert.AreEqual("b", data[1]); Assert.AreEqual("c", data[2]); + + data = new[] {"a"}; + result = Arr.Reverse(data); + + Assert.AreEqual(1, result.Length); + Assert.AreEqual("a", data); } [TestMethod] diff --git a/src/CatLib.Core/Support/Util/Arr.cs b/src/CatLib.Core/Support/Util/Arr.cs index 19ab3d8..c75d828 100644 --- a/src/CatLib.Core/Support/Util/Arr.cs +++ b/src/CatLib.Core/Support/Util/Arr.cs @@ -425,6 +425,12 @@ public static int Unshift(ref T[] source, params T[] elements) public static T[] Reverse(T[] source, int start = 0, int? length = null) { Guard.Requires(source != null); + + if (source.Length == 1) + { + return source; + } + Util.NormalizationPosition(source.Length, ref start, ref length); var tmpSource = new T[source.Length]; Array.Copy(source, tmpSource, source.Length); @@ -506,6 +512,7 @@ public static T[] Difference(T[] source, params T[] match) /// /// 移除并返回指定下标的数组元素 + /// 如果下标传入的是负数那么将会从末尾移除 /// /// 数组类型 /// 规定数组 diff --git a/src/CatLib.Core/Support/Util/Dict.cs b/src/CatLib.Core/Support/Util/Dict.cs new file mode 100644 index 0000000..d9cac74 --- /dev/null +++ b/src/CatLib.Core/Support/Util/Dict.cs @@ -0,0 +1,251 @@ +/* + * 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; +using System.Collections.Generic; + +namespace CatLib +{ + /// + /// 字典 + /// + public static class Dict + { + /// + /// 将输入字典中的每个值传给回调函数,如果回调函数返回 true,则把输入字典中的当前键值对加入结果字典中 + /// + /// 字典键类型 + /// 字典值类型 + /// 规定字典 + /// 回调函数 + /// 需求字典 + public static IDictionary Filter(IDictionary source, Predicate> predicate) + { + Guard.Requires(source != null); + Guard.Requires(predicate != null); + var elements = new Dictionary(); + + foreach (var result in source) + { + if (predicate.Invoke(result)) + { + elements[result.Key] = result.Value; + } + } + + return elements; + } + + /// + /// 将输入字典中的每个值传给回调函数,如果回调函数返回 true,则移除字典中对应的元素 + /// + /// 字典键类型 + /// 字典值类型 + /// 规定字典 + /// 回调函数 + public static void Remove(IDictionary source, Predicate> predicate) + { + Guard.Requires(source != null); + Guard.Requires(predicate != null); + + var list = new List(); + foreach (var result in source) + { + if (predicate.Invoke(result)) + { + list.Add(result.Key); + } + } + + foreach (var result in list) + { + source.Remove(result); + } + } + + /// + /// 将输入字典中的每个值传给回调函数,回调函数的返回值用于修改元素的值 + /// + /// 字典键类型 + /// 字典值类型 + /// 规定字典 + /// 回调函数 + public static void Modify(IDictionary source, Func callback) + { + Guard.Requires(source != null); + Guard.Requires(callback != null); + + Dictionary elements = null; + foreach (var result in source) + { + var value = callback.Invoke(result.Key, result.Value); + if (!result.Equals(value)) + { + elements = elements ?? new Dictionary(); + elements[result.Key] = value; + } + } + + foreach (var result in elements) + { + source[result.Key] = result.Value; + } + } + + /// + /// 批量添加到字典 + /// + /// 字典键 + /// 字典值 + /// 目标字典 + /// 增加的内容 + /// 遇到重复是否替换,如果不进行替换遇到重复将会抛出一个异常 + public static void AddRange(IDictionary source, IDictionary added, bool replaced = true) + { + Guard.Requires(source != null); + if (added == null) + { + return; + } + + foreach (var item in added) + { + if (replaced) + { + source[item.Key] = item.Value; + } + else + { + source.Add(item.Key, item.Value); + } + } + } + + /// + /// 将数组值传入用户自定义函数,自定义函数返回的值作为新的数组值 + /// + /// 数组键类型 + /// 数组值类型 + /// 规定数组 + /// 自定义函数 + /// 处理后的数组 + public static IDictionary Map(IDictionary source, Func callback) + { + Guard.Requires(source != null); + Guard.Requires(callback != null); + + var requested = new Dictionary(); + foreach (var result in source) + { + requested[result.Key] = callback.Invoke(result.Key, result.Value); + } + + return requested; + } + + /// + /// 使用点(.)来访问深度字典 + /// + /// 规定字典 + /// 键,支持使用点(.)来进行深度访问 + /// 默认值 + /// 字典值 + public static object Dot(IDictionary dict, string key, object def = null) + { + if (dict == null) + { + return def; + } + + if (key == null) + { + return dict; + } + + var keyArr = Arr.Reverse(key.Split('.')); + return GetValueByDepthArray(dict, ref keyArr) ?? def; + } + + /// + /// 使用点(.)来访问深度字典 + /// + /// 规定字典 + /// 键,支持使用点(.)来进行深度访问 + /// 默认值 + /// 字典值 + public static object Get(IDictionary dict, string key, object def = null) + { + return Dot(dict, key, def); + } + + /// + /// 使用点(.)来访问深度字典,并为其指定位置设定一个值 + /// + /// 规定字典 + /// 键,支持使用点(.)来进行深度访问 + /// 设定的值 + public static void Set(IDictionary dict, string key, object val) + { + Guard.Requires(dict != null); + Guard.Requires(key != null); + + var keyArr = Arr.Reverse(key.Split('.')); + SetValueByDepthArray(dict, ref keyArr, val); + } + + /// + /// 通过深度数组来访问字典 + /// + /// 规定字典 + /// 深度数组(深度数组以倒序传入) + /// 字典值 + private static object GetValueByDepthArray(IDictionary dict, ref string[] keys) + { + object result; + if (!dict.TryGetValue(Arr.Pop(ref keys), out result) || keys.Length <= 0) + { + return result; + } + + dict = result as IDictionary; + if (dict == null) + { + return null; + } + + return GetValueByDepthArray(dict, ref keys); + } + + /// + /// 通过深度数组来访问字典,并为其指定位置设定一个值 + /// + /// 规定字典 + /// 深度数组(深度数组以倒序传入) + /// 设定值 + private static void SetValueByDepthArray(IDictionary dict, ref string[] keys, object value) + { + if (keys.Length <= 1) + { + dict[Arr.Pop(ref keys)] = value; + return; + } + + object result; + var key = Arr.Pop(ref keys); + if (!dict.TryGetValue(key, out result) || !(result is IDictionary)) + { + dict[key] = result = new Dictionary(); + } + + SetValueByDepthArray((IDictionary) result, ref keys, value); + } + } +} From fe4401000194a63318bf0eb993f240b7f261f215 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Sun, 3 Dec 2017 13:46:34 +0800 Subject: [PATCH 21/91] container optimization --- .../CatLib.Core.NetStandard.csproj | 2 +- src/CatLib.Core/CatLib.Core.csproj | 1 + .../Support/Container/Container.cs | 108 ---------------- .../Support/Container/ContainerExtend.cs | 116 ++++++++++++++++++ .../Support/Container/IContainer.cs | 56 --------- 5 files changed, 118 insertions(+), 165 deletions(-) diff --git a/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj b/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj index 2ee4a13..fb9736c 100644 --- a/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj +++ b/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj @@ -105,6 +105,7 @@ + @@ -127,7 +128,6 @@ - diff --git a/src/CatLib.Core/CatLib.Core.csproj b/src/CatLib.Core/CatLib.Core.csproj index 7399e3e..6ec4d08 100644 --- a/src/CatLib.Core/CatLib.Core.csproj +++ b/src/CatLib.Core/CatLib.Core.csproj @@ -78,6 +78,7 @@ + diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 1970a4d..c62ae7f 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -423,114 +423,6 @@ public object Call(object instance, MethodInfo methodInfo, params object[] userP } } - /// - /// 以依赖注入的形式调用一个方法 - /// - /// 方法 - public void Call(Action method) - { - Guard.Requires(method != null); - Call(method.Target, method.Method); - } - - /// - /// 以依赖注入的形式调用一个方法 - /// - /// 方法 - public void Call(Action method) - { - Guard.Requires(method != null); - Call(method.Target, method.Method); - } - - /// - /// 以依赖注入的形式调用一个方法 - /// - /// 方法 - public void Call(Action method) - { - Guard.Requires(method != null); - Call(method.Target, method.Method); - } - - /// - /// 以依赖注入的形式调用一个方法 - /// - /// 方法 - public void Call(Action method) - { - Guard.Requires(method != null); - Call(method.Target, method.Method); - } - - /// - /// 包装一个依赖注入形式调用的一个方法 - /// - /// 方法 - /// 用户传入的参数 - /// 包装方法 - public Action Wrap(Action method, params object[] userParams) - { - return () => - { - if (method != null) - { - Call(method.Target, method.Method, userParams); - } - }; - } - - /// - /// 包装一个依赖注入形式调用的一个方法 - /// - /// 方法 - /// 用户传入的参数 - /// 包装方法 - public Action Wrap(Action method, params object[] userParams) - { - return () => - { - if (method != null) - { - Call(method.Target, method.Method, userParams); - } - }; - } - - /// - /// 包装一个依赖注入形式调用的一个方法 - /// - /// 方法 - /// 用户传入的参数 - /// 包装方法 - public Action Wrap(Action method, params object[] userParams) - { - return () => - { - if (method != null) - { - Call(method.Target, method.Method, userParams); - } - }; - } - - /// - /// 包装一个依赖注入形式调用的一个方法 - /// - /// 方法 - /// 用户传入的参数 - /// 包装方法 - public Action Wrap(Action method, params object[] userParams) - { - return () => - { - if (method != null) - { - Call(method.Target, method.Method, userParams); - } - }; - } - /// /// 构造服务 /// diff --git a/src/CatLib.Core/Support/Container/ContainerExtend.cs b/src/CatLib.Core/Support/Container/ContainerExtend.cs index 394e348..85452bd 100644 --- a/src/CatLib.Core/Support/Container/ContainerExtend.cs +++ b/src/CatLib.Core/Support/Container/ContainerExtend.cs @@ -18,6 +18,122 @@ namespace CatLib /// public static class ContainerExtend { + /// + /// 以依赖注入的形式调用一个方法 + /// + /// 服务容器 + /// 方法 + public static void Call(this IContainer container, Action method) + { + Guard.Requires(method != null); + container.Call(method.Target, method.Method); + } + + /// + /// 以依赖注入的形式调用一个方法 + /// + /// 服务容器 + /// 方法 + public static void Call(this IContainer container, Action method) + { + Guard.Requires(method != null); + container.Call(method.Target, method.Method); + } + + /// + /// 以依赖注入的形式调用一个方法 + /// + /// 服务容器 + /// 方法 + public static void Call(this IContainer container, Action method) + { + Guard.Requires(method != null); + container.Call(method.Target, method.Method); + } + + /// + /// 以依赖注入的形式调用一个方法 + /// + /// 服务容器 + /// 方法 + public static void Call(this IContainer container, Action method) + { + Guard.Requires(method != null); + container.Call(method.Target, method.Method); + } + + /// + /// 包装一个依赖注入形式调用的一个方法 + /// + /// 服务容器 + /// 方法 + /// 用户传入的参数 + /// 包装方法 + public static Action Wrap(this IContainer container, Action method, params object[] userParams) + { + return () => + { + if (method != null) + { + container.Call(method.Target, method.Method, userParams); + } + }; + } + + /// + /// 包装一个依赖注入形式调用的一个方法 + /// + /// 服务容器 + /// 方法 + /// 用户传入的参数 + /// 包装方法 + public static Action Wrap(this IContainer container, Action method, params object[] userParams) + { + return () => + { + if (method != null) + { + container.Call(method.Target, method.Method, userParams); + } + }; + } + + /// + /// 包装一个依赖注入形式调用的一个方法 + /// + /// 服务容器 + /// 方法 + /// 用户传入的参数 + /// 包装方法 + public static Action Wrap(this IContainer container, Action method, params object[] userParams) + { + return () => + { + if (method != null) + { + container.Call(method.Target, method.Method, userParams); + } + }; + } + + /// + /// 包装一个依赖注入形式调用的一个方法 + /// + /// 服务容器 + /// 方法 + /// 用户传入的参数 + /// 包装方法 + public static Action Wrap(this IContainer container, Action method, params object[] userParams) + { + return () => + { + if (method != null) + { + container.Call(method.Target, method.Method, userParams); + } + }; + } + /// /// 以单例的形式绑定一个服务 /// diff --git a/src/CatLib.Core/Support/Container/IContainer.cs b/src/CatLib.Core/Support/Container/IContainer.cs index 96481db..2432626 100644 --- a/src/CatLib.Core/Support/Container/IContainer.cs +++ b/src/CatLib.Core/Support/Container/IContainer.cs @@ -146,62 +146,6 @@ public interface IContainer /// 方法返回值 object Call(object instance, MethodInfo methodInfo, params object[] userParams); - /// - /// 以依赖注入的形式调用一个方法 - /// - /// 方法 - void Call(Action method); - - /// - /// 以依赖注入的形式调用一个方法 - /// - /// 方法 - void Call(Action method); - - /// - /// 以依赖注入的形式调用一个方法 - /// - /// 方法 - void Call(Action method); - - /// - /// 以依赖注入的形式调用一个方法 - /// - /// 方法 - void Call(Action method); - - /// - /// 包装一个依赖注入形式调用的一个方法 - /// - /// 方法 - /// 用户传入的参数 - /// 包装方法 - Action Wrap(Action method, params object[] userParams); - - /// - /// 包装一个依赖注入形式调用的一个方法 - /// - /// 方法 - /// 用户传入的参数 - /// 包装方法 - Action Wrap(Action method, params object[] userParams); - - /// - /// 包装一个依赖注入形式调用的一个方法 - /// - /// 方法 - /// 用户传入的参数 - /// 包装方法 - Action Wrap(Action method, params object[] userParams); - - /// - /// 包装一个依赖注入形式调用的一个方法 - /// - /// 方法 - /// 用户传入的参数 - /// 包装方法 - Action Wrap(Action method, params object[] userParams); - /// /// 构造服务,允许传入参数来决定构造函数的值 /// From ea1b02a69e7a6802276dc851162a5448628a6911 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Sun, 3 Dec 2017 17:01:57 +0800 Subject: [PATCH 22/91] add dict unit test --- .../CatLib.Core.Tests.csproj | 1 + .../Support/Container/ContainerTests.cs | 2 +- .../Support/Util/ArrTests.cs | 2 +- .../Support/Util/DictTests.cs | 221 ++++++++++++++++++ .../Support/Container/Container.cs | 44 ++-- .../Support/Container/ContainerExtend.cs | 18 ++ .../Support/Container/IContainer.cs | 9 - src/CatLib.Core/Support/Util/Dict.cs | 166 +++++++++---- 8 files changed, 384 insertions(+), 79 deletions(-) create mode 100644 src/CatLib.Core.Tests/Support/Util/DictTests.cs diff --git a/src/CatLib.Core.Tests/CatLib.Core.Tests.csproj b/src/CatLib.Core.Tests/CatLib.Core.Tests.csproj index de80f89..943d967 100644 --- a/src/CatLib.Core.Tests/CatLib.Core.Tests.csproj +++ b/src/CatLib.Core.Tests/CatLib.Core.Tests.csproj @@ -51,6 +51,7 @@ + diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs index 3b11dd6..5d43754 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs @@ -578,7 +578,7 @@ public void CanCallMethod() [TestMethod] public void CanCallMethodNoParam() { - var container = MakeContainer(); + var container = MakeContainer() as IContainer; container.Bind(); var cls = new CallTestClass(); diff --git a/src/CatLib.Core.Tests/Support/Util/ArrTests.cs b/src/CatLib.Core.Tests/Support/Util/ArrTests.cs index 60ecd88..d855197 100644 --- a/src/CatLib.Core.Tests/Support/Util/ArrTests.cs +++ b/src/CatLib.Core.Tests/Support/Util/ArrTests.cs @@ -461,7 +461,7 @@ public void TestReverse() result = Arr.Reverse(data); Assert.AreEqual(1, result.Length); - Assert.AreEqual("a", data); + Assert.AreEqual("a", data[0]); } [TestMethod] diff --git a/src/CatLib.Core.Tests/Support/Util/DictTests.cs b/src/CatLib.Core.Tests/Support/Util/DictTests.cs new file mode 100644 index 0000000..845377c --- /dev/null +++ b/src/CatLib.Core.Tests/Support/Util/DictTests.cs @@ -0,0 +1,221 @@ +/* + * 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.Collections.Generic; +using CatLib.Tests; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace CatLib.Core.Tests.Support.Util +{ + [TestClass] + public class DictTests + { + [TestMethod] + public void TestGet() + { + var dict = new Dictionary + { + { "my" , new Dictionary + { + {"name" , new Dictionary + { + { "is" , "catlib" } + }}, + + {"age" , new Dictionary + { + { "is" , 18 } + }}, + } } + }; + + Assert.AreEqual("catlib", Dict.Get(dict, "my.name.is")); + Assert.AreEqual(18, Dict.Get(dict, "my.age.is")); + Assert.AreEqual("undefiend", Dict.Get(dict, "my.age.undefiend","undefiend")); + + Assert.AreEqual("undefiend", Dict.Get(null, "my.age.undefiend", "undefiend")); + Assert.AreEqual(dict, Dict.Get(dict, null, "undefiend")); + + Assert.AreEqual("undefiend", Dict.Get(dict, "my.age.is.name", "undefiend")); + } + + [TestMethod] + public void TestSetRemove() + { + var dict = new Dictionary(); + + Dict.Set(dict, "hello.world", "hello"); + Dict.Set(dict, "hello.name", "catlib"); + Dict.Set(dict, "hello.world.name", "c#"); + Dict.Set(dict, "hello.world.just", "j#"); + + Assert.AreEqual(((Dictionary)dict["hello"])["world"], Dict.Get(dict, "hello.world")); + Assert.AreEqual("c#", Dict.Get(dict, "hello.world.name")); + Assert.AreEqual("j#", Dict.Get(dict, "hello.world.just")); + Assert.AreEqual("catlib", Dict.Get(dict, "hello.name")); + + Dict.Remove(dict, "hello.world.name"); + Dict.Remove(dict, "hello.world.just"); + + Assert.AreEqual("undefiend", Dict.Get(dict, "hello.world", "undefiend")); + Assert.AreEqual("catlib", Dict.Get(dict, "hello.name", "undefiend")); + + dict = new Dictionary(); + Dict.Set(dict, "hello.world.name.is", "hello"); + Dict.Remove(dict, "hello.world.name.is"); + Assert.AreEqual("undefiend", Dict.Get(dict, "hello", "undefiend")); + + Assert.AreEqual(false, Dict.Remove(dict, "notexists.notexists")); + Assert.AreEqual(false, Dict.Remove(dict, "hello.name.is.world")); + } + + [TestMethod] + public void TestKeys() + { + var dict = new Dictionary + { + {"1", 1}, + {"2", 1}, + {"3", 1} + }; + + var arr = Dict.Keys(dict); + + Assert.AreEqual("1", arr[0]); + Assert.AreEqual("2", arr[1]); + Assert.AreEqual("3", arr[2]); + } + + [TestMethod] + public void TestValues() + { + var dict = new Dictionary + { + {"1", 1}, + {"2", 2}, + {"3", 3} + }; + + var arr = Dict.Values(dict); + + Assert.AreEqual(1, arr[0]); + Assert.AreEqual(2, arr[1]); + Assert.AreEqual(3, arr[2]); + } + + [TestMethod] + public void TestMap() + { + var dict = new Dictionary + { + {"1", 1}, + {"2", 2}, + {"3", 3} + }; + + var arr = Dict.Values(Dict.Map(dict, (key, val) => val * 2)); + + Assert.AreEqual(2, arr[0]); + Assert.AreEqual(4, arr[1]); + Assert.AreEqual(6, arr[2]); + } + + [TestMethod] + public void TestModify() + { + var dict = new Dictionary + { + {"1", 1}, + {"2", 2}, + {"3", 3} + }; + + Dict.Modify(dict, (k, v) => v * 2); + + var arr = Dict.Values(dict); + + Assert.AreEqual(2, arr[0]); + Assert.AreEqual(4, arr[1]); + Assert.AreEqual(6, arr[2]); + } + + [TestMethod] + public void TestRemove() + { + var dict = new Dictionary + { + {"1", 1}, + {"2", 2}, + {"3", 3} + }; + + Dict.Remove(dict, (k, v) => v == 2); + var arr = Dict.Values(dict); + + Assert.AreEqual(1, arr[0]); + Assert.AreEqual(3, arr[1]); + } + + [TestMethod] + public void TestFilter() + { + var dict = new Dictionary + { + {"1", 1}, + {"2", 2}, + {"3", 3} + }; + + var arr = Dict.Values(Dict.Filter(dict, (k, v) => v == 2)); + Assert.AreEqual(2, arr[0]); + } + + [TestMethod] + public void TestAddRang() + { + var dict = new Dictionary + { + {"1", 1}, + {"2", 2}, + {"3", 3} + }; + + Dict.AddRange(dict, new Dictionary + { + { "9", 9 }, + { "10", 10 } + }); + + ExceptionAssert.Throws(() => + { + Dict.AddRange(dict, new Dictionary + { + {"9", 9}, + {"10", 10} + }, false); + }); + + Dict.AddRange(dict, new Dictionary + { + {"10", 12} + }); + + ExceptionAssert.DoesNotThrow(() => + { + Dict.AddRange(dict, null); + }); + + Assert.AreEqual(true, dict.ContainsKey("9")); + Assert.AreEqual(true, dict.ContainsKey("10")); + Assert.AreEqual(12, dict["10"]); + } + } +} diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index c62ae7f..e9f2080 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -66,6 +66,11 @@ public class Container : IContainer /// private readonly Dictionary findTypeCache; + /// + /// 已经被解决过的服务名 + /// + private readonly Dictionary resolved; + /// /// 方法容器 /// @@ -105,11 +110,13 @@ public Container(int prime = 32) binds = new Dictionary(prime * 4); resolving = new List>((int)(prime * 0.25)); release = new List>((int)(prime * 0.25)); + resolved = new Dictionary(prime * 4); findType = new SortSet, int>(); findTypeCache = new Dictionary(prime * 4); - injectTarget = typeof(InjectAttribute); buildStack = new Stack(32); userParamsStack = new Stack(32); + + injectTarget = typeof(InjectAttribute); methodContainer = new MethodContainer(this); } @@ -382,23 +389,6 @@ public IBindData Bind(string service, Func concret } } - /// - /// 以依赖注入形式调用一个方法 - /// - /// 方法对象 - /// 方法名 - /// 用户传入的参数 - /// 方法返回值 - /// ,null或者空字符串 - public object Call(object instance, string method, params object[] userParams) - { - Guard.NotNull(instance, "instance"); - Guard.NotEmptyOrNull(method, "method"); - - var methodInfo = instance.GetType().GetMethod(method); - return Call(instance, methodInfo, userParams); - } - /// /// 以依赖注入形式调用一个方法 /// @@ -565,26 +555,23 @@ public void Flush() { lock (syncRoot) { - var releaseList = new string[instances.Count]; - var i = 0; - foreach (var instance in instances) - { - releaseList[i++] = instance.Key; - } - foreach (var service in releaseList) + foreach (var service in Dict.Keys(instances)) { Release(service); } - binds.Clear(); - instances.Clear(); + tags.Clear(); aliases.Clear(); aliasesReverse.Clear(); - tags.Clear(); + instances.Clear(); + binds.Clear(); resolving.Clear(); release.Clear(); + resolved.Clear(); findType.Clear(); findTypeCache.Clear(); + buildStack.Clear(); + userParamsStack.Clear(); } } @@ -1088,7 +1075,6 @@ protected object[] GetDependencies(Bindable makeServiceBindData, IList /// 制作一个空的绑定数据 /// diff --git a/src/CatLib.Core/Support/Container/ContainerExtend.cs b/src/CatLib.Core/Support/Container/ContainerExtend.cs index 85452bd..a1a0488 100644 --- a/src/CatLib.Core/Support/Container/ContainerExtend.cs +++ b/src/CatLib.Core/Support/Container/ContainerExtend.cs @@ -134,6 +134,24 @@ public static Action Wrap(this IContainer container, Action + /// 以依赖注入形式调用一个方法 + /// + /// 服务容器 + /// 方法对象 + /// 方法名 + /// 用户传入的参数 + /// 方法返回值 + /// ,null或者空字符串 + public static object Call(this IContainer container, object instance, string method, params object[] userParams) + { + Guard.NotNull(instance, "instance"); + Guard.NotEmptyOrNull(method, "method"); + + var methodInfo = instance.GetType().GetMethod(method); + return container.Call(instance, methodInfo, userParams); + } + /// /// 以单例的形式绑定一个服务 /// diff --git a/src/CatLib.Core/Support/Container/IContainer.cs b/src/CatLib.Core/Support/Container/IContainer.cs index 2432626..8c6d6ca 100644 --- a/src/CatLib.Core/Support/Container/IContainer.cs +++ b/src/CatLib.Core/Support/Container/IContainer.cs @@ -128,15 +128,6 @@ public interface IContainer /// 处理释放时的回调 IContainer OnRelease(Action action); - /// - /// 以依赖注入形式调用一个方法 - /// - /// 方法对象 - /// 方法名 - /// 用户传入的参数 - /// 方法返回值 - object Call(object instance, string method, params object[] userParams); - /// /// 以依赖注入形式调用一个方法 /// diff --git a/src/CatLib.Core/Support/Util/Dict.cs b/src/CatLib.Core/Support/Util/Dict.cs index d9cac74..aa17d42 100644 --- a/src/CatLib.Core/Support/Util/Dict.cs +++ b/src/CatLib.Core/Support/Util/Dict.cs @@ -27,7 +27,8 @@ public static class Dict /// 规定字典 /// 回调函数 /// 需求字典 - public static IDictionary Filter(IDictionary source, Predicate> predicate) + public static IDictionary Filter(IDictionary source, + Func predicate) { Guard.Requires(source != null); Guard.Requires(predicate != null); @@ -35,7 +36,7 @@ public static IDictionary Filter(IDictionary Filter(IDictionary字典值类型 /// 规定字典 /// 回调函数 - public static void Remove(IDictionary source, Predicate> predicate) + public static void Remove(IDictionary source, Func predicate) { Guard.Requires(source != null); Guard.Requires(predicate != null); @@ -59,7 +60,7 @@ public static void Remove(IDictionary source, Predic var list = new List(); foreach (var result in source) { - if (predicate.Invoke(result)) + if (predicate.Invoke(result.Key, result.Value)) { list.Add(result.Key); } @@ -130,13 +131,13 @@ public static void AddRange(IDictionary source, IDic } /// - /// 将数组值传入用户自定义函数,自定义函数返回的值作为新的数组值 + /// 将字典值传入用户自定义函数,自定义函数返回的值作为新的字典值 /// - /// 数组键类型 - /// 数组值类型 - /// 规定数组 + /// 字典键类型 + /// 字典值类型 + /// 规定字典 /// 自定义函数 - /// 处理后的数组 + /// 处理后的字典 public static IDictionary Map(IDictionary source, Func callback) { Guard.Requires(source != null); @@ -151,6 +152,48 @@ public static IDictionary Map(IDictionary + /// 获取字典的键数组 + /// + /// 字典键类型 + /// 字典值类型 + /// 规定字典 + /// 字典的键数组 + public static TKey[] Keys(IDictionary source) + { + Guard.Requires(source != null); + + var keys = new TKey[source.Count]; + var i = 0; + foreach (var item in source) + { + keys[i++] = item.Key; + } + + return keys; + } + + /// + /// 获取字典的值数组 + /// + /// 字典键类型 + /// 字典值类型 + /// 规定字典 + /// 字典的值数组 + public static TValue[] Values(IDictionary source) + { + Guard.Requires(source != null); + + var keys = new TValue[source.Count]; + var i = 0; + foreach (var item in source) + { + keys[i++] = item.Value; + } + + return keys; + } + /// /// 使用点(.)来访问深度字典 /// @@ -158,14 +201,14 @@ public static IDictionary Map(IDictionary键,支持使用点(.)来进行深度访问 /// 默认值 /// 字典值 - public static object Dot(IDictionary dict, string key, object def = null) + public static object Get(IDictionary dict, string key, object def = null) { if (dict == null) { return def; } - if (key == null) + if (string.IsNullOrEmpty(key)) { return dict; } @@ -175,30 +218,32 @@ public static object Dot(IDictionary dict, string key, object de } /// - /// 使用点(.)来访问深度字典 + /// 使用点(.)来访问深度字典,并为其指定位置设定一个值 /// /// 规定字典 /// 键,支持使用点(.)来进行深度访问 - /// 默认值 - /// 字典值 - public static object Get(IDictionary dict, string key, object def = null) + /// 设定的值 + public static void Set(IDictionary dict, string key, object val) { - return Dot(dict, key, def); + Guard.Requires(dict != null); + Guard.Requires(key != null); + + var keyArr = Arr.Reverse(key.Split('.')); + SetValueByDepthArray(dict, ref keyArr, val); } /// - /// 使用点(.)来访问深度字典,并为其指定位置设定一个值 + /// 使用点(.)来访问深度字典,并移除其中一个值 /// /// 规定字典 /// 键,支持使用点(.)来进行深度访问 - /// 设定的值 - public static void Set(IDictionary dict, string key, object val) + public static bool Remove(IDictionary dict, string key) { Guard.Requires(dict != null); Guard.Requires(key != null); var keyArr = Arr.Reverse(key.Split('.')); - SetValueByDepthArray(dict, ref keyArr, val); + return RemoveValueByDepthArray(dict, ref keyArr); } /// @@ -209,19 +254,20 @@ public static void Set(IDictionary dict, string key, object val) /// 字典值 private static object GetValueByDepthArray(IDictionary dict, ref string[] keys) { - object result; - if (!dict.TryGetValue(Arr.Pop(ref keys), out result) || keys.Length <= 0) + while (true) { - return result; - } + object result; + if (!dict.TryGetValue(Arr.Pop(ref keys), out result) || keys.Length <= 0) + { + return result; + } - dict = result as IDictionary; - if (dict == null) - { - return null; + dict = result as IDictionary; + if (dict == null) + { + return null; + } } - - return GetValueByDepthArray(dict, ref keys); } /// @@ -232,20 +278,62 @@ private static object GetValueByDepthArray(IDictionary dict, ref /// 设定值 private static void SetValueByDepthArray(IDictionary dict, ref string[] keys, object value) { - if (keys.Length <= 1) + while (true) { - dict[Arr.Pop(ref keys)] = value; - return; + if (keys.Length <= 1) + { + dict[Arr.Pop(ref keys)] = value; + return; + } + + object result; + var key = Arr.Pop(ref keys); + if (!dict.TryGetValue(key, out result) || !(result is IDictionary)) + { + dict[key] = result = new Dictionary(); + } + + dict = (IDictionary)result; } + } - object result; - var key = Arr.Pop(ref keys); - if (!dict.TryGetValue(key, out result) || !(result is IDictionary)) + /// + /// 通过深度数组来移除数组中的一个值 + /// + /// 规定字典 + /// 深度数组(深度数组以倒序传入) + private static bool RemoveValueByDepthArray(IDictionary dict, ref string[] keys) + { + var perv = new Stack>>(keys.Length); + while (true) { - dict[key] = result = new Dictionary(); - } + if (keys.Length <= 1) + { + dict.Remove(Arr.Pop(ref keys)); + while (perv.Count > 0) + { + var data = perv.Pop(); + var tmpDict = (IDictionary)data.Value[data.Key]; + if (tmpDict.Count <= 0) + { + data.Value.Remove(data.Key); + continue; + } + break; + } + return true; + } - SetValueByDepthArray((IDictionary) result, ref keys, value); + object result; + var key = Arr.Pop(ref keys); + if (!dict.TryGetValue(key, out result) || !(result is IDictionary)) + { + return false; + } + + perv.Push(new KeyValuePair>(key, dict)); + dict = (IDictionary)result; + } } } } From cfe3cf4a35ad08a6dc54b5686c55944734b393b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Sun, 3 Dec 2017 18:06:15 +0800 Subject: [PATCH 23/91] add rebound(undone) --- src/CatLib.Core/Support/Container/BindData.cs | 5 ++ .../Support/Container/Container.cs | 54 +++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/src/CatLib.Core/Support/Container/BindData.cs b/src/CatLib.Core/Support/Container/BindData.cs index dffe1b0..75f0ddd 100644 --- a/src/CatLib.Core/Support/Container/BindData.cs +++ b/src/CatLib.Core/Support/Container/BindData.cs @@ -95,6 +95,11 @@ public IBindData OnResolving(Func func) resolving = new List>(); } resolving.Add(func); + + if (Container.HasInstance(Service)) + { + + } } return this; } diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index e9f2080..65351e1 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -71,6 +71,11 @@ public class Container : IContainer /// private readonly Dictionary resolved; + /// + /// 重定义事件 + /// + private readonly Dictionary>> rebound; + /// /// 方法容器 /// @@ -113,6 +118,7 @@ public Container(int prime = 32) resolved = new Dictionary(prime * 4); findType = new SortSet, int>(); findTypeCache = new Dictionary(prime * 4); + rebound = new Dictionary>>(prime); buildStack = new Stack(32); userParamsStack = new Stack(32); @@ -222,6 +228,22 @@ public bool HasInstance(string service) } } + /// + /// 服务是否已经被解决过 + /// + /// 服务名或别名 + /// 是否已经被解决过 + public bool Resolved(string service) + { + Guard.NotEmptyOrNull(service, "service"); + lock (syncRoot) + { + service = NormalizeService(service); + service = AliasToService(service); + return resolved.ContainsKey(service) || instances.ContainsKey(service); + } + } + /// /// 是否可以生成服务 /// @@ -572,6 +594,7 @@ public void Flush() findTypeCache.Clear(); buildStack.Clear(); userParamsStack.Clear(); + rebound.Clear(); } } @@ -633,6 +656,16 @@ public IContainer OnResolving(Func func) return this; } + /// + /// 当一个已经被解决的服务,发生重定义时触发 + /// + /// 回调 + /// 服务容器 + public IContainer OnRebound(Action func) + { + return this; + } + /// /// 将类型转为服务名 /// @@ -874,6 +907,25 @@ protected virtual void TriggerOnRelease(IBindData bindData, object obj) } } + /// + /// 触发服务重定义事件 + /// + /// 发生重定义的服务 + protected virtual void TriggerOnRebound(string service) + { + var instance = Make(service); + + } + + /// + /// + /// + /// + protected virtual IEnumerable> GetOnReboundCallbacks() + { + return new Action[]{}; + } + /// /// 生成一个编译失败异常 /// @@ -1118,6 +1170,8 @@ private object Resolve(string makeService, Type makeServiceType, bool isFromMake buildInstance = TriggerOnResolving(bindData, bindData.TriggerResolving(buildInstance)); } + resolved[makeService] = true; + return buildInstance; } From 45dadedc5422d13e12519aee0631b56e3d3bb40b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Sun, 3 Dec 2017 19:04:52 +0800 Subject: [PATCH 24/91] container update --- .../Support/Container/Container.cs | 63 ++++++++++++++----- 1 file changed, 46 insertions(+), 17 deletions(-) diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 65351e1..c13b17f 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -233,7 +233,7 @@ public bool HasInstance(string service) /// /// 服务名或别名 /// 是否已经被解决过 - public bool Resolved(string service) + public bool IsResolved(string service) { Guard.NotEmptyOrNull(service, "service"); lock (syncRoot) @@ -538,10 +538,17 @@ public void Instance(string service, object instance) bindData = MakeEmptyBindData(service); } + var isResolved = IsResolved(service); + Release(service); instance = TriggerOnResolving(bindData, instance); instances.Add(service, instance); + + if (isResolved) + { + TriggerOnRebound(service); + } } } @@ -617,14 +624,14 @@ public IContainer OnFindType(Func finder, int priority = int.MaxVa /// /// 当静态服务被释放时 /// - /// 处理释放时的回调 + /// 处理释放时的回调 /// 当前容器实例 - public IContainer OnRelease(Action action) + public IContainer OnRelease(Action callback) { - Guard.NotNull(action, "action"); + Guard.NotNull(callback, "callback"); lock (syncRoot) { - release.Add(action); + release.Add(callback); } return this; } @@ -632,20 +639,20 @@ public IContainer OnRelease(Action action) /// /// 当服务被解决时,生成的服务会经过注册的回调函数 /// - /// 回调函数 + /// 回调函数 /// 当前容器对象 - public IContainer OnResolving(Func func) + public IContainer OnResolving(Func callback) { - Guard.NotNull(func, "func"); + Guard.NotNull(callback, "callback"); lock (syncRoot) { - resolving.Add(func); + resolving.Add(callback); var result = new Dictionary(); foreach (var data in instances) { var bindData = GetBindFillable(data.Key); - result[data.Key] = func.Invoke(bindData, data.Value); + result[data.Key] = callback.Invoke(bindData, data.Value); } foreach (var data in result) { @@ -659,10 +666,24 @@ public IContainer OnResolving(Func func) /// /// 当一个已经被解决的服务,发生重定义时触发 /// - /// 回调 + /// 服务名 + /// 回调 /// 服务容器 - public IContainer OnRebound(Action func) + public IContainer OnRebound(string service, Action callback) { + Guard.NotNull(callback, "callback"); + lock (syncRoot) + { + service = NormalizeService(service); + service = AliasToService(service); + + List> list; + if (!rebound.TryGetValue(service, out list)) + { + rebound[service] = list = new List>(); + } + list.Add(callback); + } return this; } @@ -914,16 +935,24 @@ protected virtual void TriggerOnRelease(IBindData bindData, object obj) protected virtual void TriggerOnRebound(string service) { var instance = Make(service); - + foreach (var callback in GetOnReboundCallbacks(service)) + { + callback(this, instance); + } } /// - /// + /// 获取重定义的服务所对应的回调 /// - /// - protected virtual IEnumerable> GetOnReboundCallbacks() + /// 回调列表 + protected virtual IEnumerable> GetOnReboundCallbacks(string service) { - return new Action[]{}; + List> result; + if (!rebound.TryGetValue(service, out result)) + { + return new Action[] { }; + } + return result; } /// From 0cd9e82af73f5b394aa3ce5fe81d78dc87ace8a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Sun, 3 Dec 2017 20:15:21 +0800 Subject: [PATCH 25/91] add watch --- .../Support/Container/Container.cs | 54 +++++++++++-------- .../Support/Container/IContainer.cs | 2 + 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index c13b17f..0e16d01 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -203,13 +203,13 @@ public IBindData GetBind(string service) } /// - /// 是否已经绑定了服务(只有进行过bind才视作绑定) + /// 是否已经绑定了服务 /// /// 服务名或别名 /// 服务是否被绑定 public bool HasBind(string service) { - return GetBind(service) != null; + return GetBind(service) != null || HasInstance(service); } /// @@ -256,7 +256,7 @@ public bool CanMake(string service) { service = NormalizeService(service); service = AliasToService(service); - return HasBind(service) || HasInstance(service) || GetServiceType(service) != null; + return HasBind(service) || GetServiceType(service) != null; } } @@ -407,6 +407,11 @@ public IBindData Bind(string service, Func concret var bindData = new BindData(this, service, concrete, isStatic); binds.Add(service, bindData); + if (IsResolved(service)) + { + TriggerOnRebound(service); + } + return bindData; } } @@ -414,24 +419,24 @@ public IBindData Bind(string service, Func concret /// /// 以依赖注入形式调用一个方法 /// - /// 方法对象 + /// 方法对象 /// 方法信息 /// 用户传入的参数 /// 方法返回值 - /// ,null - public object Call(object instance, MethodInfo methodInfo, params object[] userParams) + /// ,null + public object Call(object target, MethodInfo methodInfo, params object[] userParams) { - Guard.NotNull(instance, "instance"); + Guard.NotNull(target, "instance"); Guard.NotNull(methodInfo, "methodInfo"); - var type = instance.GetType(); + var type = target.GetType(); var parameter = new List(methodInfo.GetParameters()); lock (syncRoot) { var bindData = GetBindFillable(Type2Service(type)); userParams = parameter.Count > 0 ? GetDependencies(bindData, parameter, userParams) : new object[] { }; - return methodInfo.Invoke(instance, userParams); + return methodInfo.Invoke(target, userParams); } } @@ -647,18 +652,6 @@ public IContainer OnResolving(Func callback) lock (syncRoot) { resolving.Add(callback); - - var result = new Dictionary(); - foreach (var data in instances) - { - var bindData = GetBindFillable(data.Key); - result[data.Key] = callback.Invoke(bindData, data.Value); - } - foreach (var data in result) - { - instances[data.Key] = data.Value; - } - result.Clear(); } return this; } @@ -687,6 +680,25 @@ public IContainer OnRebound(string service, Action callback) return this; } + /// + /// 关注指定的服务,当服务触发重定义时调用指定对象的指定方法 + /// 调用是以依赖注入的形式进行的 + /// + /// 关注的服务名 + /// 当服务发生重定义时调用的目标 + /// 方法名 + public void Watch(string service, object target, string method) + { + Guard.Requires(target != null); + Guard.NotEmptyOrNull(method, "method"); + + OnRebound(service, (container, instance) => + { + var methodInfo = target.GetType().GetMethod(method); + Call(target, methodInfo, container, instance); + }); + } + /// /// 将类型转为服务名 /// diff --git a/src/CatLib.Core/Support/Container/IContainer.cs b/src/CatLib.Core/Support/Container/IContainer.cs index 8c6d6ca..b24bf71 100644 --- a/src/CatLib.Core/Support/Container/IContainer.cs +++ b/src/CatLib.Core/Support/Container/IContainer.cs @@ -74,6 +74,7 @@ public interface IContainer /// /// 如果服务不存在那么则绑定服务 + /// 如果返回值为null说明没有绑定服务 /// /// 服务名 /// 服务实现 @@ -83,6 +84,7 @@ public interface IContainer /// /// 如果服务不存在那么则绑定服务 + /// 如果返回值为null说明没有绑定服务 /// /// 服务名 /// 服务实现 From af2c20e6abd186044c5d45c68ab38a9c355586c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Sun, 3 Dec 2017 20:36:04 +0800 Subject: [PATCH 26/91] rewrite BindIf api --- src/CatLib.Core/Support/Container/BindData.cs | 2 +- src/CatLib.Core/Support/Container/Container.cs | 13 ++++++++----- src/CatLib.Core/Support/Container/IContainer.cs | 4 ++-- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/CatLib.Core/Support/Container/BindData.cs b/src/CatLib.Core/Support/Container/BindData.cs index 75f0ddd..804a7e7 100644 --- a/src/CatLib.Core/Support/Container/BindData.cs +++ b/src/CatLib.Core/Support/Container/BindData.cs @@ -133,7 +133,7 @@ public IBindData OnRelease(Action action) /// protected override void ReleaseBind() { - Container.UnBind(Service); + Container.Unbind(Service); } /// diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 0e16d01..a0b5fa2 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -335,11 +335,13 @@ public IContainer Alias(string alias, string service) /// 服务名 /// 服务实现 /// 服务是否是静态的 + /// 服务绑定数据 /// 服务绑定数据 - public IBindData BindIf(string service, Func concrete, bool isStatic) + public bool BindIf(string service, Func concrete, bool isStatic, out IBindData bindData) { var bind = GetBind(service); - return bind ?? Bind(service, concrete, isStatic); + bindData = bind ?? Bind(service, concrete, isStatic); + return bind == null; } /// @@ -349,10 +351,11 @@ public IBindData BindIf(string service, Func concr /// 服务实现 /// 服务是否是静态的 /// 服务绑定数据 - public IBindData BindIf(string service, Type concrete, bool isStatic) + public bool BindIf(string service, Type concrete, bool isStatic, out IBindData bindData) { var bind = GetBind(service); - return bind ?? Bind(service, concrete, isStatic); + bindData = bind ?? Bind(service, concrete, isStatic); + return bind == null; } /// @@ -713,7 +716,7 @@ public string Type2Service(Type type) /// 解除绑定服务 /// /// 服务名或者别名 - public void UnBind(string service) + public void Unbind(string service) { lock (syncRoot) { diff --git a/src/CatLib.Core/Support/Container/IContainer.cs b/src/CatLib.Core/Support/Container/IContainer.cs index b24bf71..1841445 100644 --- a/src/CatLib.Core/Support/Container/IContainer.cs +++ b/src/CatLib.Core/Support/Container/IContainer.cs @@ -61,7 +61,7 @@ public interface IContainer /// 服务实体 /// 服务是否静态化 /// 服务绑定数据 - IBindData Bind(string service, Func concrete, bool isStatic); + bool Bind(string service, Func concrete, bool isStatic, out IBindData bindData); /// /// 绑定一个服务 @@ -70,7 +70,7 @@ public interface IContainer /// 服务实现 /// 服务是否静态化 /// 服务绑定数据 - IBindData Bind(string service, Type concrete, bool isStatic); + bool Bind(string service, Type concrete, bool isStatic, out IBindData bindData); /// /// 如果服务不存在那么则绑定服务 From 21edd125d4038c452832a1a19d66e76c134109cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Sun, 3 Dec 2017 21:28:01 +0800 Subject: [PATCH 27/91] container optimization --- .../Support/Container/ContainerTests.cs | 24 ++-- src/CatLib.Core/CatLib/App.cs | 130 ++++++++++++++++-- .../Support/Container/ContainerExtend.cs | 116 ++++++++++++++++ .../Support/Container/IContainer.cs | 45 ++++-- 4 files changed, 278 insertions(+), 37 deletions(-) diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs index 5d43754..50da1e2 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs @@ -139,10 +139,13 @@ public void NullTagService() public void CanBindIf() { var container = MakeContainer(); - var bind = container.BindIf("CanBindIf", (cont, param) => "Hello", true); - var bind2 = container.BindIf("CanBindIf", (cont, param) => "World", false); + IBindData bind1, bind2; + var result1 = container.BindIf("CanBindIf", (cont, param) => "Hello", true, out bind1); + var result2 = container.BindIf("CanBindIf", (cont, param) => "World", false,out bind2); - Assert.AreSame(bind, bind2); + Assert.AreSame(bind1, bind2); + Assert.AreEqual(true, result1); + Assert.AreEqual(false, result2); } /// @@ -152,10 +155,13 @@ public void CanBindIf() public void CanBindIfByType() { var container = MakeContainer(); - var bind = container.BindIf("CanBindIf", typeof(ContainerTest), true); - var bind2 = container.BindIf("CanBindIf", typeof(ContainerTest), false); + IBindData bind1, bind2; + var result1 = container.BindIf("CanBindIf", typeof(ContainerTest), true, out bind1); + var result2 = container.BindIf("CanBindIf", typeof(ContainerTest), false, out bind2); - Assert.AreSame(bind, bind2); + Assert.AreSame(bind1, bind2); + Assert.AreEqual(true, result1); + Assert.AreEqual(false, result2); } /// @@ -1503,9 +1509,6 @@ public void CanInstanceWithRelease() } #endregion - /// - /// 已存在的静态对象在注册新的OnResolving时会自动触发 - /// [TestMethod] public void OnResolvingExistsObject() { @@ -1517,11 +1520,10 @@ public void OnResolvingExistsObject() container.OnResolving((bind, obj) => { isCall = true; - Assert.AreSame(data, obj); return obj; }); - Assert.AreEqual(true, isCall); + Assert.AreEqual(false, isCall); } /// diff --git a/src/CatLib.Core/CatLib/App.cs b/src/CatLib.Core/CatLib/App.cs index c6b1b3b..29295fe 100644 --- a/src/CatLib.Core/CatLib/App.cs +++ b/src/CatLib.Core/CatLib/App.cs @@ -258,10 +258,11 @@ public static IBindData Bind(string service, Type concrete, bool isStatic) /// 服务名 /// 服务实现 /// 服务是否是静态的 + /// 如果绑定失败则返回历史绑定对象 /// 服务绑定数据 - public static IBindData BindIf(string service, Func concrete, bool isStatic) + public static bool BindIf(string service, Func concrete, bool isStatic, out IBindData bindData) { - return Handler.BindIf(service, concrete, isStatic); + return Handler.BindIf(service, concrete, isStatic, out bindData); } /// @@ -270,10 +271,11 @@ public static IBindData BindIf(string service, Func服务名 /// 服务实现 /// 服务是否是静态的 + /// 如果绑定失败则返回历史绑定对象 /// 服务绑定数据 - public static IBindData BindIf(string service, Type concrete, bool isStatic) + public static bool BindIf(string service, Type concrete, bool isStatic, out IBindData bindData) { - return Handler.BindIf(service, concrete, isStatic); + return Handler.BindIf(service, concrete, isStatic, out bindData); } /// @@ -352,7 +354,7 @@ public static object Call(object instance, MethodInfo methodInfo, params object[ /// 以依赖注入的形式调用一个方法 /// /// 方法 - public void Call(Action method) + public static void Call(Action method) { Handler.Call(method); } @@ -361,7 +363,7 @@ public void Call(Action method) /// 以依赖注入的形式调用一个方法 /// /// 方法 - public void Call(Action method) + public static void Call(Action method) { Handler.Call(method); } @@ -370,7 +372,7 @@ public void Call(Action method) /// 以依赖注入的形式调用一个方法 /// /// 方法 - public void Call(Action method) + public static void Call(Action method) { Handler.Call(method); } @@ -379,7 +381,7 @@ public void Call(Action method) /// 以依赖注入的形式调用一个方法 /// /// 方法 - public void Call(Action method) + public static void Call(Action method) { Handler.Call(method); } @@ -390,7 +392,7 @@ public void Call(Action method) /// 方法 /// 用户传入的参数 /// 包装方法 - public Action Wrap(Action method, params object[] userParams) + public static Action Wrap(Action method, params object[] userParams) { return Handler.Wrap(method, userParams); } @@ -401,7 +403,7 @@ public Action Wrap(Action method, params object[] userParams) /// 方法 /// 用户传入的参数 /// 包装方法 - public Action Wrap(Action method, params object[] userParams) + public static Action Wrap(Action method, params object[] userParams) { return Handler.Wrap(method, userParams); } @@ -412,7 +414,7 @@ public Action Wrap(Action method, params object[] userParams) /// 方法 /// 用户传入的参数 /// 包装方法 - public Action Wrap(Action method, params object[] userParams) + public static Action Wrap(Action method, params object[] userParams) { return Handler.Wrap(method, userParams); } @@ -423,7 +425,7 @@ public Action Wrap(Action method, params object[] userPa /// 方法 /// 用户传入的参数 /// 包装方法 - public Action Wrap(Action method, params object[] userParams) + public static Action Wrap(Action method, params object[] userParams) { return Handler.Wrap(method, userParams); } @@ -565,6 +567,58 @@ public static IBindData Singleton(Func c return Handler.Singleton(concrete); } + /// + /// 如果服务不存在那么则绑定服务 + /// + /// 服务名 + /// 服务别名 + /// 服务容器 + /// 如果绑定失败则返回历史绑定对象 + /// 是否完成绑定 + public static bool SingletonIf(out IBindData bindData) + { + return Handler.SingletonIf(out bindData); + } + + /// + /// 如果服务不存在那么则绑定服务 + /// + /// 服务名,同时也是服务实现 + /// 服务容器 + /// 如果绑定失败则返回历史绑定对象 + /// 是否完成绑定 + public static bool SingletonIf(out IBindData bindData) where TService : class + { + return Handler.SingletonIf(out bindData); + } + + /// + /// 如果服务不存在那么则绑定服务 + /// + /// 服务名 + /// 服务容器 + /// 服务实现 + /// 如果绑定失败则返回历史绑定对象 + /// 是否完成绑定 + public static bool SingletonIf(Func concrete, out IBindData bindData) + where TService : class + { + return Handler.SingletonIf(concrete, out bindData); + } + + /// + /// 如果服务不存在那么则绑定服务 + /// + /// 服务容器 + /// 服务名 + /// 服务实现 + /// 如果绑定失败则返回历史绑定对象 + /// 是否完成绑定 + public static bool SingletonIf(string service, Func concrete, out IBindData bindData) + { + return Handler.SingletonIf(service, concrete, out bindData); + } + /// /// 常规绑定一个服务 /// @@ -610,6 +664,58 @@ public static IBindData Bind(string service, return Handler.Bind(service, concrete); } + /// + /// 如果服务不存在那么则绑定服务 + /// + /// 服务名 + /// 服务别名 + /// 服务容器 + /// 如果绑定失败则返回历史绑定对象 + /// 是否完成绑定 + public static bool BindIf(out IBindData bindData) + { + return Handler.BindIf(out bindData); + } + + /// + /// 如果服务不存在那么则绑定服务 + /// + /// 服务名,同时也是服务实现 + /// 服务容器 + /// 如果绑定失败则返回历史绑定对象 + /// 是否完成绑定 + public static bool BindIf(out IBindData bindData) where TService : class + { + return Handler.BindIf(out bindData); + } + + /// + /// 如果服务不存在那么则绑定服务 + /// + /// 服务名 + /// 服务容器 + /// 服务实现 + /// 如果绑定失败则返回历史绑定对象 + /// 是否完成绑定 + public static bool BindIf(Func concrete, out IBindData bindData) + where TService : class + { + return Handler.BindIf(concrete, out bindData); + } + + /// + /// 如果服务不存在那么则绑定服务 + /// + /// 服务容器 + /// 服务名 + /// 服务实现 + /// 如果绑定失败则返回历史绑定对象 + /// 是否完成绑定 + public static bool BindIf(string service, Func concrete, out IBindData bindData) + { + return Handler.BindIf(service, concrete, out bindData); + } + /// /// 构造一个服务,允许传入构造参数 /// diff --git a/src/CatLib.Core/Support/Container/ContainerExtend.cs b/src/CatLib.Core/Support/Container/ContainerExtend.cs index a1a0488..11f1dda 100644 --- a/src/CatLib.Core/Support/Container/ContainerExtend.cs +++ b/src/CatLib.Core/Support/Container/ContainerExtend.cs @@ -202,6 +202,64 @@ public static IBindData Singleton(this IContainer container, return container.Bind(container.Type2Service(typeof(TService)), concrete, true); } + /// + /// 如果服务不存在那么则绑定服务 + /// + /// 服务名 + /// 服务别名 + /// 服务容器 + /// 如果绑定失败则返回历史绑定对象 + /// 是否完成绑定 + public static bool SingletonIf(this IContainer container, out IBindData bindData) + { + if (container.BindIf(container.Type2Service(typeof(TService)), typeof(TService), true, out bindData)) + { + bindData.Alias(container.Type2Service(typeof(TAlias))); + return true; + } + return false; + } + + /// + /// 如果服务不存在那么则绑定服务 + /// + /// 服务名,同时也是服务实现 + /// 服务容器 + /// 如果绑定失败则返回历史绑定对象 + /// 是否完成绑定 + public static bool SingletonIf(this IContainer container, out IBindData bindData) where TService : class + { + return container.BindIf(container.Type2Service(typeof(TService)), typeof(TService), true, out bindData); + } + + /// + /// 如果服务不存在那么则绑定服务 + /// + /// 服务名 + /// 服务容器 + /// 服务实现 + /// 如果绑定失败则返回历史绑定对象 + /// 是否完成绑定 + public static bool SingletonIf(this IContainer container, Func concrete, out IBindData bindData) + where TService : class + { + return container.BindIf(container.Type2Service(typeof(TService)), concrete, true, out bindData); + } + + /// + /// 如果服务不存在那么则绑定服务 + /// + /// 服务容器 + /// 服务名 + /// 服务实现 + /// 如果绑定失败则返回历史绑定对象 + /// 是否完成绑定 + public static bool SingletonIf(this IContainer container, string service, + Func concrete, out IBindData bindData) + { + return container.BindIf(service, concrete, true, out bindData); + } + /// /// 常规绑定一个服务 /// @@ -252,6 +310,64 @@ public static IBindData Bind(this IContainer container, string service, return container.Bind(service, concrete, false); } + /// + /// 如果服务不存在那么则绑定服务 + /// + /// 服务名 + /// 服务别名 + /// 服务容器 + /// 如果绑定失败则返回历史绑定对象 + /// 是否完成绑定 + public static bool BindIf(this IContainer container, out IBindData bindData) + { + if (container.BindIf(container.Type2Service(typeof(TService)), typeof(TService), false, out bindData)) + { + bindData.Alias(container.Type2Service(typeof(TAlias))); + return true; + } + return false; + } + + /// + /// 如果服务不存在那么则绑定服务 + /// + /// 服务名,同时也是服务实现 + /// 服务容器 + /// 如果绑定失败则返回历史绑定对象 + /// 是否完成绑定 + public static bool BindIf(this IContainer container,out IBindData bindData) where TService : class + { + return container.BindIf(container.Type2Service(typeof(TService)), typeof(TService), false, out bindData); + } + + /// + /// 如果服务不存在那么则绑定服务 + /// + /// 服务名 + /// 服务容器 + /// 服务实现 + /// 如果绑定失败则返回历史绑定对象 + /// 是否完成绑定 + public static bool BindIf(this IContainer container, Func concrete,out IBindData bindData) + where TService : class + { + return container.BindIf(container.Type2Service(typeof(TService)), concrete, false, out bindData); + } + + /// + /// 如果服务不存在那么则绑定服务 + /// + /// 服务容器 + /// 服务名 + /// 服务实现 + /// 如果绑定失败则返回历史绑定对象 + /// 是否完成绑定 + public static bool BindIf(this IContainer container, string service, + Func concrete,out IBindData bindData) + { + return container.BindIf(service, concrete, false, out bindData); + } + /// /// 为服务设定一个别名 /// diff --git a/src/CatLib.Core/Support/Container/IContainer.cs b/src/CatLib.Core/Support/Container/IContainer.cs index 1841445..d1bfba3 100644 --- a/src/CatLib.Core/Support/Container/IContainer.cs +++ b/src/CatLib.Core/Support/Container/IContainer.cs @@ -61,7 +61,7 @@ public interface IContainer /// 服务实体 /// 服务是否静态化 /// 服务绑定数据 - bool Bind(string service, Func concrete, bool isStatic, out IBindData bindData); + IBindData Bind(string service, Func concrete, bool isStatic); /// /// 绑定一个服务 @@ -70,27 +70,27 @@ public interface IContainer /// 服务实现 /// 服务是否静态化 /// 服务绑定数据 - bool Bind(string service, Type concrete, bool isStatic, out IBindData bindData); + IBindData Bind(string service, Type concrete, bool isStatic); /// /// 如果服务不存在那么则绑定服务 - /// 如果返回值为null说明没有绑定服务 /// /// 服务名 /// 服务实现 /// 服务是否是静态的 - /// 服务绑定数据 - IBindData BindIf(string service, Func concrete, bool isStatic); + /// 如果绑定失败则返回历史绑定对象 + /// 是否成功绑定 + bool BindIf(string service, Func concrete, bool isStatic, out IBindData bindData); /// /// 如果服务不存在那么则绑定服务 - /// 如果返回值为null说明没有绑定服务 /// /// 服务名 /// 服务实现 /// 服务是否是静态的 - /// 服务绑定数据 - IBindData BindIf(string service, Type concrete, bool isStatic); + /// 如果绑定失败则返回历史绑定对象 + /// 是否成功绑定 + bool BindIf(string service, Type concrete, bool isStatic, out IBindData bindData); /// /// 为一个及以上的服务定义一个标记 @@ -124,12 +124,6 @@ public interface IContainer /// void Flush(); - /// - /// 当静态服务被释放时 - /// - /// 处理释放时的回调 - IContainer OnRelease(Action action); - /// /// 以依赖注入形式调用一个方法 /// @@ -183,6 +177,12 @@ public interface IContainer /// 当前容器实例 IContainer OnResolving(Func func); + /// + /// 当静态服务被释放时 + /// + /// 处理释放时的回调 + IContainer OnRelease(Action action); + /// /// 当查找类型无法找到时会尝试去调用开发者提供的查找类型函数 /// @@ -191,6 +191,23 @@ public interface IContainer /// 当前容器实例 IContainer OnFindType(Func func, int priority = int.MaxValue); + /// + /// 当一个已经被解决的服务,发生重定义时触发 + /// + /// 服务名 + /// 回调 + /// 服务容器 + IContainer OnRebound(string service, Action callback); + + /// + /// 关注指定的服务,当服务触发重定义时调用指定对象的指定方法 + /// 调用是以依赖注入的形式进行的 + /// + /// 关注的服务名 + /// 当服务发生重定义时调用的目标 + /// 方法名 + void Watch(string service, object target, string method); + /// /// 类型转为服务名 /// From c6eee541678d115d144e2f62ca8ec22dbbc8882e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Sun, 3 Dec 2017 21:45:20 +0800 Subject: [PATCH 28/91] container optimization --- .../Support/Container/Container.cs | 142 +++++++++++------- 1 file changed, 90 insertions(+), 52 deletions(-) diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index a0b5fa2..9d6aba5 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -335,7 +335,7 @@ public IContainer Alias(string alias, string service) /// 服务名 /// 服务实现 /// 服务是否是静态的 - /// 服务绑定数据 + /// 如果绑定失败则返回历史绑定对象 /// 服务绑定数据 public bool BindIf(string service, Func concrete, bool isStatic, out IBindData bindData) { @@ -350,6 +350,7 @@ public bool BindIf(string service, Func concrete, /// 服务名 /// 服务实现 /// 服务是否是静态的 + /// 如果绑定失败则返回历史绑定对象 /// 服务绑定数据 public bool BindIf(string service, Type concrete, bool isStatic, out IBindData bindData) { @@ -372,7 +373,7 @@ public IBindData Bind(string service, Type concrete, bool isStatic) return Bind(service, (c, param) => { var container = (Container)c; - return container.Resolve(service, concrete, false, param); + return container.Build(service, concrete, false, param); }, isStatic); } @@ -454,35 +455,7 @@ public object Call(object target, MethodInfo methodInfo, params object[] userPar /// 服务实例,如果构造失败那么返回null public object MakeWith(string service, params object[] userParams) { - Guard.NotEmptyOrNull(service, "service"); - lock (syncRoot) - { - service = NormalizeService(service); - service = AliasToService(service); - - object instance; - if (instances.TryGetValue(service, out instance)) - { - return instance; - } - - if (buildStack.Contains(service)) - { - throw new RuntimeException("Circular dependency detected while for [" + service + "]."); - } - - buildStack.Push(service); - userParamsStack.Push(userParams); - try - { - return Resolve(service, null, true, userParams); - } - finally - { - userParamsStack.Pop(); - buildStack.Pop(); - } - } + return Resolve(service, userParams); } /// @@ -970,6 +943,21 @@ protected virtual IEnumerable> GetOnReboundCallbacks( return result; } + /// + /// 获取编译堆栈调试消息 + /// + /// + protected virtual string GetBuildStackDebugMessage() + { + if (buildStack.Count <= 0) + { + return string.Empty; + } + + var previous = string.Join(", ", buildStack.ToArray()); + return " While building [" + previous + "]."; + } + /// /// 生成一个编译失败异常 /// @@ -988,13 +976,8 @@ protected virtual UnresolvableException MakeBuildFaildException(string makeServi { message = "Service [" + makeService + "] is not exists."; } - - if (buildStack.Count > 0) - { - var previous = string.Join(", ", buildStack.ToArray()); - message += " While building [" + previous + "]."; - } + message += GetBuildStackDebugMessage(); return new UnresolvableException(message, innerException); } @@ -1010,6 +993,18 @@ protected virtual UnresolvableException MakeUnresolvablePrimitiveException(strin return new UnresolvableException(message); } + /// + /// 生成一个出现循环依赖的异常 + /// + /// 当前服务名 + /// 运行时异常 + protected virtual RuntimeException MakeCircularDependencyException(string service) + { + var message = "Circular dependency detected while for [" + service + "]."; + message += GetBuildStackDebugMessage(); + return new RuntimeException(message); + } + /// /// 标准化服务名 /// @@ -1181,19 +1176,73 @@ protected BindData MakeEmptyBindData(string service) return new BindData(this, service, null, false); } + /// + /// 获取别名最终对应的服务名 + /// + /// 服务名或别名 + /// 最终映射的服务名 + protected virtual string AliasToService(string service) + { + string alias; + return aliases.TryGetValue(service, out alias) ? alias : service; + } + /// /// 解决服务 /// + /// 服务名或别名 + /// 用户传入的构造参数 + /// 服务实例,如果构造失败那么返回null + /// null或者空字符串 + /// 出现循环依赖 + /// 无法解决服务 + /// 服务实例 + private object Resolve(string service, params object[] userParams) + { + Guard.NotEmptyOrNull(service, "service"); + lock (syncRoot) + { + service = NormalizeService(service); + service = AliasToService(service); + + object instance; + if (instances.TryGetValue(service, out instance)) + { + return instance; + } + + if (buildStack.Contains(service)) + { + throw new RuntimeException("Circular dependency detected while for [" + service + "]."); + } + + buildStack.Push(service); + userParamsStack.Push(userParams); + try + { + return Build(service, null, true, userParams); + } + finally + { + userParamsStack.Pop(); + buildStack.Pop(); + } + } + } + + /// + /// 编译服务 + /// /// 服务名 /// 服务类型 /// 是否直接调用自Make函数 /// 用户传入的构造参数 /// 服务实例 - private object Resolve(string makeService, Type makeServiceType, bool isFromMake, params object[] userParams) + private object Build(string makeService, Type makeServiceType, bool isFromMake, params object[] userParams) { var bindData = GetBindFillable(makeService); var buildInstance = isFromMake ? BuildUseConcrete(bindData, makeServiceType, userParams) - : Build(bindData, makeServiceType ?? (makeServiceType = GetServiceType(bindData.Service)), userParams); + : CreateInstance(bindData, makeServiceType ?? (makeServiceType = GetServiceType(bindData.Service)), userParams); GuardResolveInstance(buildInstance, makeService, makeServiceType); @@ -1226,7 +1275,7 @@ private object Resolve(string makeService, Type makeServiceType, bool isFromMake /// 服务类型 /// 用户传入的构造参数 /// 服务实例 - private object Build(BindData makeServiceBindData, Type makeServiceType, object[] userParams) + private object CreateInstance(BindData makeServiceBindData, Type makeServiceType, object[] userParams) { userParams = userParams ?? new object[] { }; @@ -1278,18 +1327,7 @@ private object BuildUseConcrete(BindData makeServiceBindData, Type makeServiceTy { return makeServiceBindData.Concrete != null ? makeServiceBindData.Concrete(this, param) : - Resolve(makeServiceBindData.Service, makeServiceType, false, param); - } - - /// - /// 获取别名最终对应的服务名 - /// - /// 服务名或别名 - /// 最终映射的服务名 - private string AliasToService(string service) - { - string alias; - return aliases.TryGetValue(service, out alias) ? alias : service; + Build(makeServiceBindData.Service, makeServiceType, false, param); } /// From 069d8dba5f8b27051797a5922aa7009ca41b3944 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Mon, 4 Dec 2017 08:41:08 +0800 Subject: [PATCH 29/91] add rebound unit test --- .../Support/Container/ContainerTests.cs | 39 +++++++++++++++++++ .../Support/Container/Container.cs | 22 +++++------ .../Support/Container/IContainer.cs | 2 +- 3 files changed, 51 insertions(+), 12 deletions(-) diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs index 50da1e2..bb127dd 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs @@ -1665,6 +1665,45 @@ public int TestContainerCall(int num) return num; } + #region Rebound + [TestMethod] + public void TestOnRebound() + { + var container = new Container(); + var callRebound = false; + container.OnRebound("TestService", (instance) => + { + Assert.AreEqual(300, instance); + callRebound = true; + }); + + container.Bind("TestService", (c, p) => 100).UnBind(); + var bind = container.Bind("TestService", (c, p) => 200); + container.Make("TestService"); + bind.UnBind(); + container.Bind("TestService", (c, p) => 300); + + Assert.AreEqual(true, callRebound); + } + + [TestMethod] + public void TestOnReboundWithInstance() + { + var container = new Container(); + var callRebound = false; + container.OnRebound("TestService", (instance) => + { + Assert.AreEqual(300, instance); + callRebound = true; + }); + + container.Instance("TestService", 100); + container.Instance("TestService", 300); + + Assert.AreEqual(true, callRebound); + } + #endregion + /// /// 生成容器 /// diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 9d6aba5..e22fd31 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -74,7 +74,7 @@ public class Container : IContainer /// /// 重定义事件 /// - private readonly Dictionary>> rebound; + private readonly Dictionary>> rebound; /// /// 方法容器 @@ -118,7 +118,7 @@ public Container(int prime = 32) resolved = new Dictionary(prime * 4); findType = new SortSet, int>(); findTypeCache = new Dictionary(prime * 4); - rebound = new Dictionary>>(prime); + rebound = new Dictionary>>(prime); buildStack = new Stack(32); userParamsStack = new Stack(32); @@ -638,7 +638,7 @@ public IContainer OnResolving(Func callback) /// 服务名 /// 回调 /// 服务容器 - public IContainer OnRebound(string service, Action callback) + public IContainer OnRebound(string service, Action callback) { Guard.NotNull(callback, "callback"); lock (syncRoot) @@ -646,10 +646,10 @@ public IContainer OnRebound(string service, Action callback) service = NormalizeService(service); service = AliasToService(service); - List> list; + List> list; if (!rebound.TryGetValue(service, out list)) { - rebound[service] = list = new List>(); + rebound[service] = list = new List>(); } list.Add(callback); } @@ -668,10 +668,10 @@ public void Watch(string service, object target, string method) Guard.Requires(target != null); Guard.NotEmptyOrNull(method, "method"); - OnRebound(service, (container, instance) => + OnRebound(service, (instance) => { var methodInfo = target.GetType().GetMethod(method); - Call(target, methodInfo, container, instance); + Call(target, methodInfo, instance); }); } @@ -925,7 +925,7 @@ protected virtual void TriggerOnRebound(string service) var instance = Make(service); foreach (var callback in GetOnReboundCallbacks(service)) { - callback(this, instance); + callback(instance); } } @@ -933,12 +933,12 @@ protected virtual void TriggerOnRebound(string service) /// 获取重定义的服务所对应的回调 /// /// 回调列表 - protected virtual IEnumerable> GetOnReboundCallbacks(string service) + protected virtual IEnumerable> GetOnReboundCallbacks(string service) { - List> result; + List> result; if (!rebound.TryGetValue(service, out result)) { - return new Action[] { }; + return new Action[] { }; } return result; } diff --git a/src/CatLib.Core/Support/Container/IContainer.cs b/src/CatLib.Core/Support/Container/IContainer.cs index d1bfba3..dbd319f 100644 --- a/src/CatLib.Core/Support/Container/IContainer.cs +++ b/src/CatLib.Core/Support/Container/IContainer.cs @@ -197,7 +197,7 @@ public interface IContainer /// 服务名 /// 回调 /// 服务容器 - IContainer OnRebound(string service, Action callback); + IContainer OnRebound(string service, Action callback); /// /// 关注指定的服务,当服务触发重定义时调用指定对象的指定方法 From 99d4f4ba79e8042e0693fc66f3459b418c908810 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Tue, 5 Dec 2017 16:17:13 +0800 Subject: [PATCH 30/91] exception message update --- src/CatLib.Core/Support/Container/Container.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index e22fd31..c901a2c 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -970,7 +970,7 @@ protected virtual UnresolvableException MakeBuildFaildException(string makeServi string message; if (makeServiceType != null) { - message = "Target [" + makeServiceType + "] build faild. Service is [" + makeService + "]"; + message = "Target [" + makeServiceType + "] build faild. Service is [" + makeService + "]."; } else { From 686ad5ac5a2ac88f06ab28a6fb7139f37251168b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Tue, 5 Dec 2017 20:44:39 +0800 Subject: [PATCH 31/91] container update --- .../Support/Container/ContainerTests.cs | 28 +++++++++++++++++++ .../Support/Container/Container.cs | 7 +---- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs index bb127dd..1d8f80b 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs @@ -1702,6 +1702,34 @@ public void TestOnReboundWithInstance() Assert.AreEqual(true, callRebound); } + + public class TestWatchCLass + { + public int value; + + public IContainer container; + + public void OnChange(int instance,IContainer container) + { + value = instance; + this.container = container; + } + } + + [TestMethod] + public void TestWatch() + { + var container = new Container(); + + container.Instance(container); + var cls = new TestWatchCLass(); + container.Watch("WatchService", cls, "OnChange"); + container.Instance("WatchService", 100); + container.Instance("WatchService", 200); + + Assert.AreEqual(200, cls.value); + Assert.AreSame(container, cls.container); + } #endregion /// diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index c901a2c..7be3f03 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -949,11 +949,6 @@ protected virtual IEnumerable> GetOnReboundCallbacks(string servi /// protected virtual string GetBuildStackDebugMessage() { - if (buildStack.Count <= 0) - { - return string.Empty; - } - var previous = string.Join(", ", buildStack.ToArray()); return " While building [" + previous + "]."; } @@ -1213,7 +1208,7 @@ private object Resolve(string service, params object[] userParams) if (buildStack.Contains(service)) { - throw new RuntimeException("Circular dependency detected while for [" + service + "]."); + throw MakeCircularDependencyException(service); } buildStack.Push(service); From e59f76977f88b8edaccd205bff9e89309b388356 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Wed, 6 Dec 2017 20:36:12 +0800 Subject: [PATCH 32/91] code optimization (remove unused code) --- .../Support/Container/ContainerHelperTests.cs | 17 +++++++++++++ src/CatLib.Core/CatLib/App.cs | 25 ++++++------------- .../Support/Container/ContainerExtend.cs | 15 +++++------ 3 files changed, 30 insertions(+), 27 deletions(-) diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerHelperTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerHelperTests.cs index f56a848..a8e41cc 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerHelperTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerHelperTests.cs @@ -122,6 +122,23 @@ public void TestRelease() Assert.AreSame(obj.GetType(), container.Make().GetType()); } + [TestMethod] + public void TestBindIf() + { + var app = new Application(); + IBindData bindData; + Assert.AreEqual(true, App.BindIf("TestBind", (c, p) => 1, out bindData)); + Assert.AreEqual(false, App.BindIf("TestBind", (c, p) => 2, out bindData)); + Assert.AreEqual(1, app["TestBind"]); + + Assert.AreEqual(true, App.BindIf(out bindData)); + Assert.AreEqual(typeof(object), app.Make().GetType()); + + Assert.AreEqual(true, App.BindIf((c, p) => 100, out bindData)); + } + + + /// /// 生成容器 /// diff --git a/src/CatLib.Core/CatLib/App.cs b/src/CatLib.Core/CatLib/App.cs index 29295fe..b891bb5 100644 --- a/src/CatLib.Core/CatLib/App.cs +++ b/src/CatLib.Core/CatLib/App.cs @@ -551,7 +551,7 @@ public static IBindData Singleton() /// /// 服务名,同时也是服务实现 /// 服务绑定数据 - public static IBindData Singleton() where TService : class + public static IBindData Singleton() { return Handler.Singleton(); } @@ -562,7 +562,7 @@ public static IBindData Singleton() where TService : class /// 服务名 /// 服务实现 /// 服务绑定数据 - public static IBindData Singleton(Func concrete) where TService : class + public static IBindData Singleton(Func concrete) { return Handler.Singleton(concrete); } @@ -572,7 +572,6 @@ public static IBindData Singleton(Func c /// /// 服务名 /// 服务别名 - /// 服务容器 /// 如果绑定失败则返回历史绑定对象 /// 是否完成绑定 public static bool SingletonIf(out IBindData bindData) @@ -584,10 +583,9 @@ public static bool SingletonIf(out IBindData bindData) /// 如果服务不存在那么则绑定服务 /// /// 服务名,同时也是服务实现 - /// 服务容器 /// 如果绑定失败则返回历史绑定对象 /// 是否完成绑定 - public static bool SingletonIf(out IBindData bindData) where TService : class + public static bool SingletonIf(out IBindData bindData) { return Handler.SingletonIf(out bindData); } @@ -596,12 +594,10 @@ public static bool SingletonIf(out IBindData bindData) where TService /// 如果服务不存在那么则绑定服务 /// /// 服务名 - /// 服务容器 /// 服务实现 /// 如果绑定失败则返回历史绑定对象 /// 是否完成绑定 public static bool SingletonIf(Func concrete, out IBindData bindData) - where TService : class { return Handler.SingletonIf(concrete, out bindData); } @@ -609,7 +605,6 @@ public static bool SingletonIf(Func conc /// /// 如果服务不存在那么则绑定服务 /// - /// 服务容器 /// 服务名 /// 服务实现 /// 如果绑定失败则返回历史绑定对象 @@ -635,7 +630,7 @@ public static IBindData Bind() /// /// 服务名,同时也是服务实现 /// 服务绑定数据 - public static IBindData Bind() where TService : class + public static IBindData Bind() { return Handler.Bind(); } @@ -647,7 +642,6 @@ public static IBindData Bind() where TService : class /// 服务实现 /// 服务绑定数据 public static IBindData Bind(Func concrete) - where TService : class { return Handler.Bind(concrete); } @@ -669,7 +663,6 @@ public static IBindData Bind(string service, /// /// 服务名 /// 服务别名 - /// 服务容器 /// 如果绑定失败则返回历史绑定对象 /// 是否完成绑定 public static bool BindIf(out IBindData bindData) @@ -681,10 +674,9 @@ public static bool BindIf(out IBindData bindData) /// 如果服务不存在那么则绑定服务 /// /// 服务名,同时也是服务实现 - /// 服务容器 /// 如果绑定失败则返回历史绑定对象 /// 是否完成绑定 - public static bool BindIf(out IBindData bindData) where TService : class + public static bool BindIf(out IBindData bindData) { return Handler.BindIf(out bindData); } @@ -693,12 +685,10 @@ public static bool BindIf(out IBindData bindData) where TService : cla /// 如果服务不存在那么则绑定服务 /// /// 服务名 - /// 服务容器 /// 服务实现 /// 如果绑定失败则返回历史绑定对象 /// 是否完成绑定 public static bool BindIf(Func concrete, out IBindData bindData) - where TService : class { return Handler.BindIf(concrete, out bindData); } @@ -706,7 +696,6 @@ public static bool BindIf(Func concrete, /// /// 如果服务不存在那么则绑定服务 /// - /// 服务容器 /// 服务名 /// 服务实现 /// 如果绑定失败则返回历史绑定对象 @@ -752,7 +741,7 @@ public static TConvert Make(string service) /// 释放服务 /// /// 服务名 - public static void Release() where TService : class + public static void Release() { Handler.Release(); } @@ -762,7 +751,7 @@ public static void Release() where TService : class /// /// 服务名 /// 实例值 - public static void Instance(object instance) where TService : class + public static void Instance(object instance) { Handler.Instance(instance); } diff --git a/src/CatLib.Core/Support/Container/ContainerExtend.cs b/src/CatLib.Core/Support/Container/ContainerExtend.cs index 11f1dda..6124087 100644 --- a/src/CatLib.Core/Support/Container/ContainerExtend.cs +++ b/src/CatLib.Core/Support/Container/ContainerExtend.cs @@ -184,7 +184,7 @@ public static IBindData Singleton(this IContainer container) /// 服务名,同时也是服务实现 /// 服务容器 /// 服务绑定数据 - public static IBindData Singleton(this IContainer container) where TService : class + public static IBindData Singleton(this IContainer container) { return container.Bind(container.Type2Service(typeof(TService)), typeof(TService), true); } @@ -197,7 +197,7 @@ public static IBindData Singleton(this IContainer container) where TSe /// 服务实现 /// 服务绑定数据 public static IBindData Singleton(this IContainer container, - Func concrete) where TService : class + Func concrete) { return container.Bind(container.Type2Service(typeof(TService)), concrete, true); } @@ -227,7 +227,7 @@ public static bool SingletonIf(this IContainer container, out /// 服务容器 /// 如果绑定失败则返回历史绑定对象 /// 是否完成绑定 - public static bool SingletonIf(this IContainer container, out IBindData bindData) where TService : class + public static bool SingletonIf(this IContainer container, out IBindData bindData) { return container.BindIf(container.Type2Service(typeof(TService)), typeof(TService), true, out bindData); } @@ -240,8 +240,7 @@ public static bool SingletonIf(this IContainer container, out IBindDat /// 服务实现 /// 如果绑定失败则返回历史绑定对象 /// 是否完成绑定 - public static bool SingletonIf(this IContainer container, Func concrete, out IBindData bindData) - where TService : class + public static bool SingletonIf(this IContainer container, Func concrete, out IBindData bindData) { return container.BindIf(container.Type2Service(typeof(TService)), concrete, true, out bindData); } @@ -279,7 +278,7 @@ public static IBindData Bind(this IContainer container) /// 服务名,同时也是服务实现 /// 服务容器 /// 服务绑定数据 - public static IBindData Bind(this IContainer container) where TService : class + public static IBindData Bind(this IContainer container) { return container.Bind(container.Type2Service(typeof(TService)), typeof(TService), false); } @@ -292,7 +291,6 @@ public static IBindData Bind(this IContainer container) where TService /// 服务实现 /// 服务绑定数据 public static IBindData Bind(this IContainer container, Func concrete) - where TService : class { return container.Bind(container.Type2Service(typeof(TService)), concrete, false); } @@ -335,7 +333,7 @@ public static bool BindIf(this IContainer container, out IBind /// 服务容器 /// 如果绑定失败则返回历史绑定对象 /// 是否完成绑定 - public static bool BindIf(this IContainer container,out IBindData bindData) where TService : class + public static bool BindIf(this IContainer container,out IBindData bindData) { return container.BindIf(container.Type2Service(typeof(TService)), typeof(TService), false, out bindData); } @@ -349,7 +347,6 @@ public static bool BindIf(this IContainer container,out IBindData bind /// 如果绑定失败则返回历史绑定对象 /// 是否完成绑定 public static bool BindIf(this IContainer container, Func concrete,out IBindData bindData) - where TService : class { return container.BindIf(container.Type2Service(typeof(TService)), concrete, false, out bindData); } From 218a3f58715234ae0871c9133c6f7665dda2c8b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Thu, 7 Dec 2017 09:23:52 +0800 Subject: [PATCH 33/91] add unit test --- .../Support/Container/ContainerHelperTests.cs | 24 +++++++++++++++++++ .../Support/Container/Container.cs | 7 +++--- .../Container/UnresolvableException.cs | 1 + 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerHelperTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerHelperTests.cs index a8e41cc..779405b 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerHelperTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerHelperTests.cs @@ -135,9 +135,33 @@ public void TestBindIf() Assert.AreEqual(typeof(object), app.Make().GetType()); Assert.AreEqual(true, App.BindIf((c, p) => 100, out bindData)); + Assert.AreEqual(true, App.BindIf(out bindData)); + + Assert.AreEqual(typeof(double), App.Make(App.Type2Service(typeof(float))).GetType()); } + [TestMethod] + public void TestSingletonIf() + { + var testObject = new object(); + var testObject2 = new object(); + var app = new Application(); + IBindData bindData; + Assert.AreEqual(true, App.SingletonIf("TestBind", (c, p) => new object(), out bindData)); + + var makeObject = app["TestBind"]; + Assert.AreEqual(false, App.SingletonIf("TestBind", (c, p) => testObject2, out bindData)); + Assert.AreSame(testObject.GetType(), makeObject.GetType()); + Assert.AreSame(makeObject, app["TestBind"]); + + Assert.AreEqual(true, App.SingletonIf(out bindData)); + Assert.AreEqual(typeof(object), app.Make().GetType()); + Assert.AreEqual(true, App.SingletonIf((c, p) => 100, out bindData)); + Assert.AreEqual(true, App.SingletonIf(out bindData)); + + Assert.AreEqual(typeof(double), App.Make(App.Type2Service(typeof(float))).GetType()); + } /// /// 生成容器 diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 7be3f03..1f3c6de 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -1239,14 +1239,15 @@ private object Build(string makeService, Type makeServiceType, bool isFromMake, var buildInstance = isFromMake ? BuildUseConcrete(bindData, makeServiceType, userParams) : CreateInstance(bindData, makeServiceType ?? (makeServiceType = GetServiceType(bindData.Service)), userParams); - GuardResolveInstance(buildInstance, makeService, makeServiceType); - - //只有是来自于make函数的调用时才执行di,包装,以及修饰 + // 只有是来自于make函数的调用时才执行di,包装,以及修饰 + // 不要在这个之前执行任何调用否则在返回时这些调用会再次被执行 if (!isFromMake) { return buildInstance; } + GuardResolveInstance(buildInstance, makeService, makeServiceType); + AttributeInject(bindData, buildInstance); if (bindData.IsStatic) diff --git a/src/CatLib.Core/Support/Container/UnresolvableException.cs b/src/CatLib.Core/Support/Container/UnresolvableException.cs index 9061a09..2d1bb5e 100644 --- a/src/CatLib.Core/Support/Container/UnresolvableException.cs +++ b/src/CatLib.Core/Support/Container/UnresolvableException.cs @@ -16,6 +16,7 @@ namespace CatLib /// /// 未能解决异常 /// + [ExcludeFromCodeCoverage] public class UnresolvableException : RuntimeException { /// From 0632683d61c3a8cc018e848d2adab84065d9d44a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Thu, 7 Dec 2017 15:01:11 +0800 Subject: [PATCH 34/91] remove Container.MakeWith --- .../CatLib/ApplicationTests.cs | 2 +- .../Support/Container/ContainerTests.cs | 6 +-- src/CatLib.Core/CatLib/App.cs | 25 +------------ .../Support/Container/Container.cs | 23 +++--------- .../Support/Container/ContainerExtend.cs | 37 ++++--------------- .../Support/Container/IContainer.cs | 11 +----- 6 files changed, 20 insertions(+), 84 deletions(-) diff --git a/src/CatLib.Core.Tests/CatLib/ApplicationTests.cs b/src/CatLib.Core.Tests/CatLib/ApplicationTests.cs index 8efa32a..6be7681 100644 --- a/src/CatLib.Core.Tests/CatLib/ApplicationTests.cs +++ b/src/CatLib.Core.Tests/CatLib/ApplicationTests.cs @@ -120,7 +120,7 @@ public void GetVersionTest() public void MakeAssemblyClass() { var app = new Application(); - var lru = app.MakeWith>(10); + var lru = app.Make>(10); Assert.AreNotEqual(null, lru); } diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs index 1d8f80b..9e05cb2 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs @@ -818,7 +818,7 @@ public void MakeNotClassConstructor() Assert.AreEqual(77, result.I); Assert.AreNotEqual(null, result.Dependency); - var result2 = container.MakeWith(100); + var result2 = container.Make(100); Assert.AreEqual(100, result2.I); Assert.AreNotEqual(null, result2.Dependency); } @@ -838,7 +838,7 @@ public void CanMake() Assert.AreEqual(typeof(MakeTestClass), result.GetType()); var dep = new MakeTestClassDependency(); - var result2 = container.MakeWith(dep); + var result2 = container.Make(dep); Assert.AreEqual(typeof(MakeTestClass), result2.GetType()); var result3 = container[container.Type2Service(typeof(MakeTestClass))] as MakeTestClass; @@ -1578,7 +1578,7 @@ public void TestMakeWithParams() { var container = MakeContainer(); container.Bind(); - Assert.AreEqual(typeof(TestParamsMakeClass), container.MakeWith(null).GetType()); + Assert.AreEqual(typeof(TestParamsMakeClass), container.Make(null).GetType()); } [TestMethod] diff --git a/src/CatLib.Core/CatLib/App.cs b/src/CatLib.Core/CatLib/App.cs index b891bb5..976d6dd 100644 --- a/src/CatLib.Core/CatLib/App.cs +++ b/src/CatLib.Core/CatLib/App.cs @@ -436,19 +436,9 @@ public static Action Wrap(Action method, params /// 服务名或别名 /// 用户传入的参数 /// 服务实例,如果构造失败那么返回null - public static object MakeWith(string service, params object[] userParams) + public static object Make(string service, params object[] userParams) { - return Handler.MakeWith(service, userParams); - } - - /// - /// 构造服务 - /// - /// 服务名或别名 - /// 服务实例,如果构造失败那么返回null - public static object Make(string service) - { - return Handler.Make(service); + return Handler.Make(service, userParams); } /// @@ -705,17 +695,6 @@ public static bool BindIf(string service, Func con return Handler.BindIf(service, concrete, out bindData); } - /// - /// 构造一个服务,允许传入构造参数 - /// - /// 服务名 - /// 构造参数 - /// 服务实例 - public static TService MakeWith(params object[] param) - { - return Handler.MakeWith(param); - } - /// /// 构造一个服务 /// diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 1f3c6de..a0d5f75 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -449,27 +449,14 @@ public object Call(object target, MethodInfo methodInfo, params object[] userPar /// /// 服务名或别名 /// 用户传入的构造参数 - /// 服务实例,如果构造失败那么返回null /// null或者空字符串 /// 出现循环依赖 /// 服务实例,如果构造失败那么返回null - public object MakeWith(string service, params object[] userParams) + public object Make(string service, params object[] userParams) { return Resolve(service, userParams); } - /// - /// 构造服务 - /// - /// 服务名或别名 - /// null或者空字符串 - /// 出现循环依赖 - /// 服务实例,如果构造失败那么返回null - public object Make(string service) - { - return MakeWith(service); - } - /// /// 构造服务 /// @@ -802,7 +789,7 @@ protected virtual object ResolveAttrPrimitive(Bindable makeServiceBindData } var result = SpeculationServiceByParamName(makeServiceBindData, baseParam.Name); - if(result != null) + if (result != null) { return result; } @@ -829,7 +816,7 @@ protected virtual object ResloveAttrClass(Bindable makeServiceBindData, st /// 希望解决的服务名或者别名 /// 当前正在解决的变量 /// 解决结果 - protected virtual object ResolvePrimitive(Bindable makeServiceBindData, string service , ParameterInfo baseParam) where T : class, IBindable + protected virtual object ResolvePrimitive(Bindable makeServiceBindData, string service, ParameterInfo baseParam) where T : class, IBindable { service = makeServiceBindData.GetContextual(service); if (CanMake(service)) @@ -838,7 +825,7 @@ protected virtual object ResolvePrimitive(Bindable makeServiceBindData, st } var result = SpeculationServiceByParamName(makeServiceBindData, baseParam.Name); - if(result != null) + if (result != null) { return result; } @@ -1039,7 +1026,7 @@ protected virtual void GuardUserParamsCount(int count) /// 服务实例 /// 服务名 /// 服务类型 - protected virtual void GuardResolveInstance(object instance,string makeService, Type makeServiceType) + protected virtual void GuardResolveInstance(object instance, string makeService, Type makeServiceType) { if (instance == null) { diff --git a/src/CatLib.Core/Support/Container/ContainerExtend.cs b/src/CatLib.Core/Support/Container/ContainerExtend.cs index 6124087..644f856 100644 --- a/src/CatLib.Core/Support/Container/ContainerExtend.cs +++ b/src/CatLib.Core/Support/Container/ContainerExtend.cs @@ -240,7 +240,7 @@ public static bool SingletonIf(this IContainer container, out IBindDat /// 服务实现 /// 如果绑定失败则返回历史绑定对象 /// 是否完成绑定 - public static bool SingletonIf(this IContainer container, Func concrete, out IBindData bindData) + public static bool SingletonIf(this IContainer container, Func concrete, out IBindData bindData) { return container.BindIf(container.Type2Service(typeof(TService)), concrete, true, out bindData); } @@ -333,7 +333,7 @@ public static bool BindIf(this IContainer container, out IBind /// 服务容器 /// 如果绑定失败则返回历史绑定对象 /// 是否完成绑定 - public static bool BindIf(this IContainer container,out IBindData bindData) + public static bool BindIf(this IContainer container, out IBindData bindData) { return container.BindIf(container.Type2Service(typeof(TService)), typeof(TService), false, out bindData); } @@ -346,7 +346,7 @@ public static bool BindIf(this IContainer container,out IBindData bind /// 服务实现 /// 如果绑定失败则返回历史绑定对象 /// 是否完成绑定 - public static bool BindIf(this IContainer container, Func concrete,out IBindData bindData) + public static bool BindIf(this IContainer container, Func concrete, out IBindData bindData) { return container.BindIf(container.Type2Service(typeof(TService)), concrete, false, out bindData); } @@ -360,7 +360,7 @@ public static bool BindIf(this IContainer container, Func如果绑定失败则返回历史绑定对象 /// 是否完成绑定 public static bool BindIf(this IContainer container, string service, - Func concrete,out IBindData bindData) + Func concrete, out IBindData bindData) { return container.BindIf(service, concrete, false, out bindData); } @@ -377,39 +377,16 @@ public static IContainer Alias(this IContainer container, string alias return container.Alias(alias, container.Type2Service(typeof(TService))); } - /// - /// 构造一个服务,允许传入构造参数 - /// - /// 服务名 - /// 服务容器 - /// 构造参数 - /// 服务实例 - public static TService MakeWith(this IContainer container, params object[] param) - { - return (TService) container.MakeWith(container.Type2Service(typeof(TService)), param); - } - /// /// 构造一个服务 /// /// 服务名 /// 服务容器 + /// 用户提供的参数 /// 服务实例 - public static TService Make(this IContainer container) - { - return (TService) container.Make(container.Type2Service(typeof(TService))); - } - - /// - /// 构造一个服务 - /// - /// 服务实例转换到的类型 - /// 服务容器 - /// 服务名或者别名 - /// 服务实例 - public static TConvert Make(this IContainer container, string service) + public static TService Make(this IContainer container, params object[] userParams) { - return (TConvert) container.Make(service); + return (TService)container.Make(container.Type2Service(typeof(TService)), userParams); } /// diff --git a/src/CatLib.Core/Support/Container/IContainer.cs b/src/CatLib.Core/Support/Container/IContainer.cs index dbd319f..a198851 100644 --- a/src/CatLib.Core/Support/Container/IContainer.cs +++ b/src/CatLib.Core/Support/Container/IContainer.cs @@ -133,20 +133,13 @@ public interface IContainer /// 方法返回值 object Call(object instance, MethodInfo methodInfo, params object[] userParams); - /// - /// 构造服务,允许传入参数来决定构造函数的值 - /// - /// 服务名或别名 - /// 用户传入的参数 - /// 服务实例,如果构造失败那么返回null - object MakeWith(string service, params object[] userParams); - /// /// 构造服务 /// /// 服务名或别名 + /// 用户传入的参数 /// 服务实例,如果构造失败那么返回null - object Make(string service); + object Make(string service, params object[] userParams); /// /// 构造服务 From a2123dfad9140e280bf353063d5c57a51822d1fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Thu, 7 Dec 2017 15:12:03 +0800 Subject: [PATCH 35/91] bug fixed --- src/CatLib.Core/CatLib/App.cs | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/src/CatLib.Core/CatLib/App.cs b/src/CatLib.Core/CatLib/App.cs index 976d6dd..94c1e45 100644 --- a/src/CatLib.Core/CatLib/App.cs +++ b/src/CatLib.Core/CatLib/App.cs @@ -699,21 +699,11 @@ public static bool BindIf(string service, Func con /// 构造一个服务 /// /// 服务名 + /// 用户参数 /// 服务实例 - public static TService Make() + public static TService Make(params object[] userParams) { - return Handler.Make(); - } - - /// - /// 构造一个服务 - /// - /// 服务实例转换到的类型 - /// 服务名 - /// 服务实例 - public static TConvert Make(string service) - { - return Handler.Make(service); + return Handler.Make(userParams); } /// From c5b82877ca222c42ed06937d3b5ea0ac3efb5951 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Thu, 7 Dec 2017 20:38:35 +0800 Subject: [PATCH 36/91] method container update --- .../Support/Container/MethodContainer.cs | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/CatLib.Core/Support/Container/MethodContainer.cs b/src/CatLib.Core/Support/Container/MethodContainer.cs index 109480e..0eae9ff 100644 --- a/src/CatLib.Core/Support/Container/MethodContainer.cs +++ b/src/CatLib.Core/Support/Container/MethodContainer.cs @@ -9,6 +9,10 @@ * Document: http://catlib.io/ */ +using System; +using System.Collections.Generic; +using System.Reflection; + namespace CatLib { /// @@ -16,6 +20,16 @@ namespace CatLib /// internal sealed class MethodContainer { + /// + /// 调用方法目标 映射到 方法名字 + /// + private Dictionary> targetToMethodMappings; + + /// + /// 方法映射 + /// + private Dictionary methodMappings; + /// /// 依赖注入容器 /// @@ -28,6 +42,8 @@ internal sealed class MethodContainer internal MethodContainer(Container container) { this.container = container; + targetToMethodMappings = new Dictionary>(); + methodMappings = new Dictionary(); } /// @@ -39,7 +55,21 @@ internal MethodContainer(Container container) /// public IMethodBindData BindMethod(string method, object target, string call) { + Guard.NotEmptyOrNull(method, "method"); + Guard.Requires(target != null); + Guard.NotEmptyOrNull(call, "call"); return null; - } + } + + /// + /// 生成对象中被调用方法的方法信息 + /// + /// 方法调用目标 + /// 在方法调用目标中被调用的方法 + private MethodInfo MakeMethodInfo(object target, string call) + { + return target.GetType().GetMethod(call, + BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy); + } } } From 2f8eb171bd8a77de9692e69d76fab19feda74b4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Fri, 8 Dec 2017 17:37:41 +0800 Subject: [PATCH 37/91] method container update(undone) --- .../CatLib.Core.NetStandard.csproj | 5 +- .../Support/Container/BindDataTests.cs | 6 +- .../Support/Container/ContainerTests.cs | 6 +- src/CatLib.Core/CatLib.Core.csproj | 4 +- src/CatLib.Core/Support/Container/BindData.cs | 2 +- src/CatLib.Core/Support/Container/Bindable.cs | 109 +++--- .../Support/Container/Container.cs | 309 +++++++++++------- .../Support/Container/ContainerExtend.cs | 29 +- .../Support/Container/GivenData.cs | 3 +- .../Support/Container/IBindable.cs | 10 +- .../Support/Container/IContainer.cs | 4 +- .../{IMethodBindData.cs => IMethodBind.cs} | 2 +- .../Support/Container/MethodBind.cs | 82 +++++ .../Support/Container/MethodBindData.cs | 37 --- .../Support/Container/MethodContainer.cs | 56 +++- 15 files changed, 418 insertions(+), 246 deletions(-) rename src/CatLib.Core/Support/Container/{IMethodBindData.cs => IMethodBind.cs} (84%) create mode 100644 src/CatLib.Core/Support/Container/MethodBind.cs delete mode 100644 src/CatLib.Core/Support/Container/MethodBindData.cs diff --git a/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj b/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj index fb9736c..5eada51 100644 --- a/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj +++ b/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj @@ -74,9 +74,9 @@ - + - + @@ -128,7 +128,6 @@ - diff --git a/src/CatLib.Core.Tests/Support/Container/BindDataTests.cs b/src/CatLib.Core.Tests/Support/Container/BindDataTests.cs index fb0f170..627abc4 100644 --- a/src/CatLib.Core.Tests/Support/Container/BindDataTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/BindDataTests.cs @@ -194,7 +194,7 @@ public void CheckIllegalResolving() } #endregion - #region UnBind + #region Unbind /// /// 能够正常解除绑定 /// @@ -205,7 +205,7 @@ public void CanUnBind() var bindData = container.Bind("CanUnBind", (app, param) => "hello world", false); Assert.AreEqual("hello world", container.Make("CanUnBind").ToString()); - bindData.UnBind(); + bindData.Unbind(); ExceptionAssert.Throws(() => { @@ -221,7 +221,7 @@ public void CheckIllegalUnBindInput() { var container = new Container(); var bindData = container.Bind("CanUnBind", (app, param) => "hello world", false); - bindData.UnBind(); + bindData.Unbind(); ExceptionAssert.Throws(() => { diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs index 9e05cb2..d8f2150 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs @@ -1024,7 +1024,7 @@ public void CanParamUseInjectAttr() cls = container.Make(); Assert.AreEqual("hello", cls.GetMsg()); - subBind.UnBind(); + subBind.Unbind(); cls = container.Make(); Assert.AreEqual("hello", cls.GetMsg()); } @@ -1677,10 +1677,10 @@ public void TestOnRebound() callRebound = true; }); - container.Bind("TestService", (c, p) => 100).UnBind(); + container.Bind("TestService", (c, p) => 100).Unbind(); var bind = container.Bind("TestService", (c, p) => 200); container.Make("TestService"); - bind.UnBind(); + bind.Unbind(); container.Bind("TestService", (c, p) => 300); Assert.AreEqual(true, callRebound); diff --git a/src/CatLib.Core/CatLib.Core.csproj b/src/CatLib.Core/CatLib.Core.csproj index 6ec4d08..ad0815b 100644 --- a/src/CatLib.Core/CatLib.Core.csproj +++ b/src/CatLib.Core/CatLib.Core.csproj @@ -47,8 +47,8 @@ - - + + diff --git a/src/CatLib.Core/Support/Container/BindData.cs b/src/CatLib.Core/Support/Container/BindData.cs index 804a7e7..7debed9 100644 --- a/src/CatLib.Core/Support/Container/BindData.cs +++ b/src/CatLib.Core/Support/Container/BindData.cs @@ -17,7 +17,7 @@ namespace CatLib /// /// 服务绑定数据 /// - public sealed class BindData : Bindable, IBindData + internal sealed class BindData : Bindable, IBindData { /// /// 服务实现,执行这个委托将会获得服务实例 diff --git a/src/CatLib.Core/Support/Container/Bindable.cs b/src/CatLib.Core/Support/Container/Bindable.cs index b69ffe1..892fc45 100644 --- a/src/CatLib.Core/Support/Container/Bindable.cs +++ b/src/CatLib.Core/Support/Container/Bindable.cs @@ -16,13 +16,18 @@ namespace CatLib /// /// 可绑定对象 /// - public abstract class Bindable : IBindable where TReturn : class, IBindable + public abstract class Bindable : IBindable { /// /// 当前绑定的名字 /// public string Service { get; private set; } + /// + /// 父级容器 + /// + protected readonly Container Container; + /// /// 服务关系上下文 /// 当前服务需求某个服务时可以指定给与什么服务 @@ -30,25 +35,15 @@ public abstract class Bindable : IBindable where TReturn : cla private Dictionary contextual; /// - /// 给与数据 + /// 同步锁 /// - private GivenData given; + protected readonly object SyncRoot = new object(); /// /// 是否被释放 /// private bool isDestroy; - /// - /// 父级容器 - /// - protected readonly Container Container; - - /// - /// 同步锁 - /// - protected readonly object SyncRoot = new object(); - /// /// 构建一个绑定数据 /// @@ -62,33 +57,15 @@ protected Bindable(Container container, string service) } /// - /// 当需求某个服务 + /// 解除绑定 /// - /// 服务名 - /// 绑定关系临时数据 - public IGivenData Needs(string service) + public void Unbind() { - Guard.NotEmptyOrNull(service, "service"); lock (SyncRoot) { - GuardIsDestroy(); - if (given == null) - { - given = new GivenData(Container, this); - } - given.Needs(service); + isDestroy = true; + ReleaseBind(); } - return given; - } - - /// - /// 当需求某个服务 - /// - /// 服务类型 - /// 绑定关系临时数据 - public IGivenData Needs() - { - return Needs(Container.Type2Service(typeof(T))); } /// @@ -97,7 +74,7 @@ public IGivenData Needs() /// 需求什么服务 /// 给与什么服务 /// 服务绑定数据 - internal Bindable AddContextual(string needs, string given) + internal void AddContextual(string needs, string given) { lock (SyncRoot) { @@ -111,7 +88,6 @@ internal Bindable AddContextual(string needs, string given) throw new RuntimeException("Needs [" + needs + "] is already exist."); } contextual.Add(needs, given); - return this; } } @@ -133,29 +109,68 @@ internal string GetContextual(string needs) /// /// 解除绑定 /// - public void UnBind() + protected abstract void ReleaseBind(); + + /// + /// 守卫是否被释放 + /// + protected void GuardIsDestroy() { - lock (SyncRoot) + if (isDestroy) { - isDestroy = true; - ReleaseBind(); + throw new RuntimeException("Current bind has be mark Destroy."); } } + } + /// + /// 可绑定对象 + /// + internal abstract class Bindable : Bindable, IBindable where TReturn : class, IBindable + { /// - /// 解除绑定 + /// 给与数据 /// - protected abstract void ReleaseBind(); + private GivenData given; /// - /// 守卫是否被释放 + /// 构建一个绑定数据 /// - protected void GuardIsDestroy() + /// 依赖注入容器 + /// 服务名 + protected Bindable(Container container, string service) + : base(container, service) { - if (isDestroy) + } + + /// + /// 当需求某个服务 + /// + /// 服务名 + /// 绑定关系临时数据 + public IGivenData Needs(string service) + { + Guard.NotEmptyOrNull(service, "service"); + lock (SyncRoot) { - throw new RuntimeException("Current Instance has be mark Destroy."); + GuardIsDestroy(); + if (given == null) + { + given = new GivenData(Container, this); + } + given.Needs(service); } + return given; + } + + /// + /// 当需求某个服务 + /// + /// 服务类型 + /// 绑定关系临时数据 + public IGivenData Needs() + { + return Needs(Container.Type2Service(typeof(T))); } } } diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index a0d5f75..6c7e61f 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -123,7 +123,7 @@ public Container(int prime = 32) userParamsStack = new Stack(32); injectTarget = typeof(InjectAttribute); - methodContainer = new MethodContainer(this); + methodContainer = new MethodContainer(this, GetDependencies); } /// @@ -195,7 +195,7 @@ public IBindData GetBind(string service) Guard.NotEmptyOrNull(service, "service"); lock (syncRoot) { - service = NormalizeService(service); + service = FormatService(service); service = AliasToService(service); BindData bindData; return binds.TryGetValue(service, out bindData) ? bindData : null; @@ -222,7 +222,7 @@ public bool HasInstance(string service) Guard.NotEmptyOrNull(service, "service"); lock (syncRoot) { - service = NormalizeService(service); + service = FormatService(service); service = AliasToService(service); return instances.ContainsKey(service); } @@ -238,7 +238,7 @@ public bool IsResolved(string service) Guard.NotEmptyOrNull(service, "service"); lock (syncRoot) { - service = NormalizeService(service); + service = FormatService(service); service = AliasToService(service); return resolved.ContainsKey(service) || instances.ContainsKey(service); } @@ -254,7 +254,7 @@ public bool CanMake(string service) Guard.NotEmptyOrNull(service, "service"); lock (syncRoot) { - service = NormalizeService(service); + service = FormatService(service); service = AliasToService(service); return HasBind(service) || GetServiceType(service) != null; } @@ -299,8 +299,8 @@ public IContainer Alias(string alias, string service) throw new RuntimeException("Alias is Same as Service Name: [" + alias + "]."); } - alias = NormalizeService(alias); - service = NormalizeService(service); + alias = FormatService(alias); + service = FormatService(service); lock (syncRoot) { @@ -390,7 +390,7 @@ public IBindData Bind(string service, Func concret { Guard.NotEmptyOrNull(service, "service"); Guard.NotNull(concrete, "concrete"); - service = NormalizeService(service); + service = FormatService(service); lock (syncRoot) { if (binds.ContainsKey(service)) @@ -434,16 +434,27 @@ public object Call(object target, MethodInfo methodInfo, params object[] userPar Guard.NotNull(methodInfo, "methodInfo"); var type = target.GetType(); - var parameter = new List(methodInfo.GetParameters()); + var parameter = methodInfo.GetParameters(); lock (syncRoot) { var bindData = GetBindFillable(Type2Service(type)); - userParams = parameter.Count > 0 ? GetDependencies(bindData, parameter, userParams) : new object[] { }; + userParams = parameter.Length > 0 ? GetDependencies(bindData, parameter, userParams) : new object[] { }; return methodInfo.Invoke(target, userParams); } } + /// + /// 调用一个已经被绑定的方法 + /// + /// 方法名 + /// 用户提供的参数 + /// 调用结果 + public object Invoke(string method, params object[] userParams) + { + return methodContainer.Invoke(method, userParams); + } + /// /// 构造服务 /// @@ -489,7 +500,7 @@ public void Instance(string service, object instance) Guard.NotEmptyOrNull(service, "service"); lock (syncRoot) { - service = NormalizeService(service); + service = FormatService(service); service = AliasToService(service); var bindData = GetBind(service); @@ -529,7 +540,7 @@ public void Release(string service) Guard.NotEmptyOrNull(service, "service"); lock (syncRoot) { - service = NormalizeService(service); + service = FormatService(service); service = AliasToService(service); object instance; @@ -620,7 +631,7 @@ public IContainer OnResolving(Func callback) } /// - /// 当一个已经被解决的服务,发生重定义时触发 + /// 当一个已经被解决的服务发生重定义时触发 /// /// 服务名 /// 回调 @@ -630,7 +641,7 @@ public IContainer OnRebound(string service, Action callback) Guard.NotNull(callback, "callback"); lock (syncRoot) { - service = NormalizeService(service); + service = FormatService(service); service = AliasToService(service); List> list; @@ -649,29 +660,18 @@ public IContainer OnRebound(string service, Action callback) /// /// 关注的服务名 /// 当服务发生重定义时调用的目标 - /// 方法名 - public void Watch(string service, object target, string method) + /// 方法信息 + public void Watch(string service, object target, MethodInfo methodInfo) { Guard.Requires(target != null); - Guard.NotEmptyOrNull(method, "method"); + Guard.Requires(methodInfo != null); OnRebound(service, (instance) => { - var methodInfo = target.GetType().GetMethod(method); Call(target, methodInfo, instance); }); } - /// - /// 将类型转为服务名 - /// - /// 类型 - /// 服务名 - public string Type2Service(Type type) - { - return type.ToString(); - } - /// /// 解除绑定服务 /// @@ -680,7 +680,7 @@ public void Unbind(string service) { lock (syncRoot) { - service = NormalizeService(service); + service = FormatService(service); service = AliasToService(service); Release(service); @@ -697,6 +697,16 @@ public void Unbind(string service) } } + /// + /// 将类型转为服务名 + /// + /// 类型 + /// 服务名 + public virtual string Type2Service(Type type) + { + return type.ToString(); + } + /// /// 从用户传入的参数中获取依赖 /// @@ -720,21 +730,41 @@ protected virtual object GetDependenciesFromUserParams(ParameterInfo baseParam, return Arr.RemoveAt(ref userParams, n); } - try + object result; + if (TryChangeType(userParam, baseParam.ParameterType, out result)) { - if (baseParam.ParameterType.IsPrimitive && userParam is IConvertible) - { - var result = Convert.ChangeType(userParam, baseParam.ParameterType); - Arr.RemoveAt(ref userParams, n); - return result; - } + Arr.RemoveAt(ref userParams, n); + return result; } - catch (Exception) + } + + return null; + } + + /// + /// 安全的转换参数 + /// + /// 参数 + /// 转换到的类型 + /// 转换后的结果 + /// 是否转换成功 + protected virtual bool TryChangeType(object param, Type conversionType, out object result) + { + try + { + if (conversionType.IsPrimitive && param is IConvertible) { + result = Convert.ChangeType(param, conversionType); + return true; } } + catch (Exception) + { + // ignored + } - return null; + result = null; + return false; } /// @@ -780,7 +810,7 @@ protected virtual string GetParamNeedsService(ParameterInfo baseParam) /// 希望解决的服务名或者别名 /// 当前正在解决的变量 /// 解决结果 - protected virtual object ResolveAttrPrimitive(Bindable makeServiceBindData, string service, PropertyInfo baseParam) where T : class, IBindable + protected virtual object ResolveAttrPrimitive(Bindable makeServiceBindData, string service, PropertyInfo baseParam) { service = makeServiceBindData.GetContextual(service); if (CanMake(service)) @@ -804,7 +834,7 @@ protected virtual object ResolveAttrPrimitive(Bindable makeServiceBindData /// 希望解决的服务名或者别名 /// 当前正在解决的变量 /// 解决结果 - protected virtual object ResloveAttrClass(Bindable makeServiceBindData, string service, PropertyInfo baseParam) where T : class, IBindable + protected virtual object ResloveAttrClass(Bindable makeServiceBindData, string service, PropertyInfo baseParam) { return Make(makeServiceBindData.GetContextual(service)); } @@ -816,7 +846,7 @@ protected virtual object ResloveAttrClass(Bindable makeServiceBindData, st /// 希望解决的服务名或者别名 /// 当前正在解决的变量 /// 解决结果 - protected virtual object ResolvePrimitive(Bindable makeServiceBindData, string service, ParameterInfo baseParam) where T : class, IBindable + protected virtual object ResolvePrimitive(Bindable makeServiceBindData, string service, ParameterInfo baseParam) { service = makeServiceBindData.GetContextual(service); if (CanMake(service)) @@ -845,7 +875,7 @@ protected virtual object ResolvePrimitive(Bindable makeServiceBindData, st /// 希望解决的服务名或者别名 /// 当前正在解决的变量 /// 解决结果 - protected virtual object ResloveClass(Bindable makeServiceBindData, string service, ParameterInfo baseParam) where T : class, IBindable + protected virtual object ResloveClass(Bindable makeServiceBindData, string service, ParameterInfo baseParam) { try { @@ -864,72 +894,15 @@ protected virtual object ResloveClass(Bindable makeServiceBindData, string /// /// 根据参数名字来推测服务 /// - /// /// 请求注入操作的服务绑定数据 /// 参数名 /// 推测的服务 - protected virtual object SpeculationServiceByParamName(Bindable makeServiceBindData, string paramName) where T : class, IBindable + protected virtual object SpeculationServiceByParamName(Bindable makeServiceBindData, string paramName) { var service = makeServiceBindData.GetContextual("@" + paramName); return CanMake(service) ? Make(service) : null; } - /// - /// 触发全局解决修饰器 - /// - /// 服务绑定数据 - /// 服务实例 - /// 被修饰器修饰后的服务实例 - protected virtual object TriggerOnResolving(IBindData bindData, object obj) - { - foreach (var func in resolving) - { - obj = func(bindData, obj); - } - return obj; - } - - /// - /// 触发全局释放修饰器 - /// - /// 服务绑定数据 - /// 服务实例 - /// 被修饰器修饰后的服务实例 - protected virtual void TriggerOnRelease(IBindData bindData, object obj) - { - foreach (var action in release) - { - action.Invoke(bindData, obj); - } - } - - /// - /// 触发服务重定义事件 - /// - /// 发生重定义的服务 - protected virtual void TriggerOnRebound(string service) - { - var instance = Make(service); - foreach (var callback in GetOnReboundCallbacks(service)) - { - callback(instance); - } - } - - /// - /// 获取重定义的服务所对应的回调 - /// - /// 回调列表 - protected virtual IEnumerable> GetOnReboundCallbacks(string service) - { - List> result; - if (!rebound.TryGetValue(service, out result)) - { - return new Action[] { }; - } - return result; - } - /// /// 获取编译堆栈调试消息 /// @@ -988,11 +961,11 @@ protected virtual RuntimeException MakeCircularDependencyException(string servic } /// - /// 标准化服务名 + /// 格式化服务名 /// /// 服务名 - /// 标准化后的服务名 - protected virtual string NormalizeService(string service) + /// 格式化后的服务名 + protected virtual string FormatService(string service) { return service.Trim(); } @@ -1067,7 +1040,7 @@ protected virtual Type GetServiceType(string service) /// 服务实例 /// 服务实例 /// 属性是必须的或者注入类型和需求类型不一致 - protected void AttributeInject(Bindable makeServiceBindData, object makeServiceInstance) where T : class, IBindable + protected virtual void AttributeInject(Bindable makeServiceBindData, object makeServiceInstance) { if (makeServiceInstance == null) { @@ -1112,16 +1085,16 @@ protected void AttributeInject(Bindable makeServiceBindData, object makeSe /// 输入的构造参数列表 /// 服务所需参数的解决结果 /// 生成的实例类型和需求类型不一致 - protected object[] GetDependencies(Bindable makeServiceBindData, IList baseParams, object[] userParams) where T : class, IBindable + protected virtual object[] GetDependencies(Bindable makeServiceBindData, IList baseParams, object[] userParams) { var results = new List(); foreach (var baseParam in baseParams) { - var instance = GetDependenciesFromUserParams(baseParam, ref userParams); - if (instance != null) + var param = GetDependenciesFromUserParams(baseParam, ref userParams); + if (param != null) { - results.Add(instance); + results.Add(param); continue; } @@ -1130,34 +1103,24 @@ protected object[] GetDependencies(Bindable makeServiceBindData, IList - /// 制作一个空的绑定数据 - /// - /// 服务名 - /// 空绑定数据 - protected BindData MakeEmptyBindData(string service) - { - return new BindData(this, service, null, false); - } - /// /// 获取别名最终对应的服务名 /// @@ -1169,6 +1132,104 @@ protected virtual string AliasToService(string service) return aliases.TryGetValue(service, out alias) ? alias : service; } + /// + /// 触发全局解决修饰器 + /// + /// 服务绑定数据 + /// 服务实例 + /// 被修饰器修饰后的服务实例 + private object TriggerOnResolving(IBindData bindData, object obj) + { + foreach (var func in resolving) + { + obj = func(bindData, obj); + } + return obj; + } + + /// + /// 触发全局释放修饰器 + /// + /// 服务绑定数据 + /// 服务实例 + /// 被修饰器修饰后的服务实例 + private void TriggerOnRelease(IBindData bindData, object obj) + { + foreach (var action in release) + { + action.Invoke(bindData, obj); + } + } + + /// + /// 触发服务重定义事件 + /// + /// 发生重定义的服务 + private void TriggerOnRebound(string service) + { + var instance = Make(service); + var bind = GetBind(service); + + Flash(() => + { + foreach (var callback in GetOnReboundCallbacks(service)) + { + callback(instance); + } + }, Type2Service(typeof(IBindData)), bind); + } + + /// + /// 在回调区间内暂时性的静态化一个服务实例 + /// + /// 回调区间 + /// 服务名 + /// 实例 + private void Flash(Action callback, string service, object instance) + { + lock (syncRoot) + { + if (HasInstance(service)) + { + throw new RuntimeException("Flash service [" + service + "] is already exists."); + } + + try + { + Instance(service, instance); + callback.Invoke(); + } + finally + { + Release(service); + } + } + } + + /// + /// 获取重定义的服务所对应的回调 + /// + /// 回调列表 + private IEnumerable> GetOnReboundCallbacks(string service) + { + List> result; + if (!rebound.TryGetValue(service, out result)) + { + return new Action[] { }; + } + return result; + } + + /// + /// 制作一个空的绑定数据 + /// + /// 服务名 + /// 空绑定数据 + private BindData MakeEmptyBindData(string service) + { + return new BindData(this, service, null, false); + } + /// /// 解决服务 /// @@ -1184,7 +1245,7 @@ private object Resolve(string service, params object[] userParams) Guard.NotEmptyOrNull(service, "service"); lock (syncRoot) { - service = NormalizeService(service); + service = FormatService(service); service = AliasToService(service); object instance; diff --git a/src/CatLib.Core/Support/Container/ContainerExtend.cs b/src/CatLib.Core/Support/Container/ContainerExtend.cs index 644f856..72a2a1d 100644 --- a/src/CatLib.Core/Support/Container/ContainerExtend.cs +++ b/src/CatLib.Core/Support/Container/ContainerExtend.cs @@ -138,18 +138,18 @@ public static Action Wrap(this IContainer container, Action /// 服务容器 - /// 方法对象 + /// 方法对象 /// 方法名 /// 用户传入的参数 /// 方法返回值 - /// ,null或者空字符串 - public static object Call(this IContainer container, object instance, string method, params object[] userParams) + /// ,null或者空字符串 + public static object Call(this IContainer container, object target, string method, params object[] userParams) { - Guard.NotNull(instance, "instance"); + Guard.Requires(target != null); Guard.NotEmptyOrNull(method, "method"); - var methodInfo = instance.GetType().GetMethod(method); - return container.Call(instance, methodInfo, userParams); + var methodInfo = target.GetType().GetMethod(method); + return container.Call(target, methodInfo, userParams); } /// @@ -432,5 +432,22 @@ public static void Instance(this IContainer container, object instance { container.Instance(container.Type2Service(typeof(TService)), instance); } + + /// + /// 关注指定的服务,当服务触发重定义时调用指定对象的指定方法 + /// 调用是以依赖注入的形式进行的 + /// + /// 服务容器 + /// 关注的服务名 + /// 当服务发生重定义时调用的目标 + /// 方法名 + public static void Watch(this IContainer container, string service, object target, string method) + { + Guard.Requires(target != null); + Guard.NotEmptyOrNull(method, "method"); + + var methodInfo = target.GetType().GetMethod(method); + container.Watch(service, target, methodInfo); + } } } \ No newline at end of file diff --git a/src/CatLib.Core/Support/Container/GivenData.cs b/src/CatLib.Core/Support/Container/GivenData.cs index 90b671d..a2dcbe4 100644 --- a/src/CatLib.Core/Support/Container/GivenData.cs +++ b/src/CatLib.Core/Support/Container/GivenData.cs @@ -61,7 +61,8 @@ internal IGivenData Needs(string needs) public TReturn Given(string service) { Guard.NotEmptyOrNull(service , "service"); - return bindable.AddContextual(needs, service) as TReturn; + bindable.AddContextual(needs, service); + return bindable as TReturn; } /// diff --git a/src/CatLib.Core/Support/Container/IBindable.cs b/src/CatLib.Core/Support/Container/IBindable.cs index 1b3102f..51afe23 100644 --- a/src/CatLib.Core/Support/Container/IBindable.cs +++ b/src/CatLib.Core/Support/Container/IBindable.cs @@ -14,7 +14,7 @@ namespace CatLib /// /// 被绑定对象 /// - public interface IBindable + public interface IBindable { /// /// 当前绑定的名字 @@ -25,8 +25,14 @@ public interface IBindable /// 移除绑定 /// 如果进行的是服务绑定 , 那么在解除绑定时如果是静态化物体将会触发释放 /// - void UnBind(); + void Unbind(); + } + /// + /// 被绑定对象 + /// + public interface IBindable : IBindable + { /// /// 当需求某个服务 /// diff --git a/src/CatLib.Core/Support/Container/IContainer.cs b/src/CatLib.Core/Support/Container/IContainer.cs index a198851..172a88d 100644 --- a/src/CatLib.Core/Support/Container/IContainer.cs +++ b/src/CatLib.Core/Support/Container/IContainer.cs @@ -198,8 +198,8 @@ public interface IContainer /// /// 关注的服务名 /// 当服务发生重定义时调用的目标 - /// 方法名 - void Watch(string service, object target, string method); + /// 方法信息 + void Watch(string service, object target, MethodInfo methodInfo); /// /// 类型转为服务名 diff --git a/src/CatLib.Core/Support/Container/IMethodBindData.cs b/src/CatLib.Core/Support/Container/IMethodBind.cs similarity index 84% rename from src/CatLib.Core/Support/Container/IMethodBindData.cs rename to src/CatLib.Core/Support/Container/IMethodBind.cs index 3bca075..c72a4f7 100644 --- a/src/CatLib.Core/Support/Container/IMethodBindData.cs +++ b/src/CatLib.Core/Support/Container/IMethodBind.cs @@ -14,7 +14,7 @@ namespace CatLib /// /// 方法绑定数据 /// - public interface IMethodBindData : IBindable + public interface IMethodBind : IBindable { } } diff --git a/src/CatLib.Core/Support/Container/MethodBind.cs b/src/CatLib.Core/Support/Container/MethodBind.cs new file mode 100644 index 0000000..b73d52a --- /dev/null +++ b/src/CatLib.Core/Support/Container/MethodBind.cs @@ -0,0 +1,82 @@ +/* + * 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.Reflection; + +namespace CatLib +{ + /// + /// 方法绑定数据 + /// + internal sealed class MethodBind : Bindable , IMethodBind + { + /// + /// 方法信息 + /// + private readonly MethodInfo methodInfo; + + /// + /// 方法信息 + /// + public MethodInfo MethodInfo + { + get { return methodInfo; } + } + + /// + /// 调用目标 + /// + private readonly object target; + + /// + /// 调用目标 + /// + public object Target + { + get { return target; } + } + + /// + /// 参数表 + /// + private readonly ParameterInfo[] parameterInfos; + + /// + /// 参数表 + /// + public ParameterInfo[] ParameterInfos + { + get { return parameterInfos; } + } + + /// + /// 构建一个绑定数据 + /// + /// 依赖注入容器 + /// 服务名 + /// 调用目标 + /// 调用信息 + public MethodBind(Container container, string service, object target, MethodInfo call) + :base(container, service) + { + this.target = target; + methodInfo = call; + parameterInfos = methodInfo.GetParameters(); + } + + /// + /// 解除绑定 + /// + protected override void ReleaseBind() + { + } + } +} diff --git a/src/CatLib.Core/Support/Container/MethodBindData.cs b/src/CatLib.Core/Support/Container/MethodBindData.cs deleted file mode 100644 index e31a154..0000000 --- a/src/CatLib.Core/Support/Container/MethodBindData.cs +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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/ - */ - -namespace CatLib -{ - /// - /// 方法绑定数据 - /// - internal sealed class MethodBindData : Bindable , IMethodBindData - { - /// - /// 构建一个绑定数据 - /// - /// 依赖注入容器 - /// 服务名 - public MethodBindData(Container container, string service) - :base(container, service) - { - } - - /// - /// 解除绑定 - /// - protected override void ReleaseBind() - { - - } - } -} diff --git a/src/CatLib.Core/Support/Container/MethodContainer.cs b/src/CatLib.Core/Support/Container/MethodContainer.cs index 0eae9ff..e566526 100644 --- a/src/CatLib.Core/Support/Container/MethodContainer.cs +++ b/src/CatLib.Core/Support/Container/MethodContainer.cs @@ -23,27 +23,34 @@ internal sealed class MethodContainer /// /// 调用方法目标 映射到 方法名字 /// - private Dictionary> targetToMethodMappings; + private Dictionary> targetToMethodsMappings; /// - /// 方法映射 + /// 绑定数据 /// - private Dictionary methodMappings; + private Dictionary methodMappings; /// /// 依赖注入容器 /// private Container container; + /// + /// 依赖解决器 + /// + private readonly Func, object[], object[]> dependenciesResolved; + /// /// 构建一个新的方法容器 /// /// - internal MethodContainer(Container container) + /// 依赖解决器 + internal MethodContainer(Container container, Func, object[], object[]> dependenciesResolved) { this.container = container; - targetToMethodMappings = new Dictionary>(); - methodMappings = new Dictionary(); + targetToMethodsMappings = new Dictionary>(); + methodMappings = new Dictionary(); + this.dependenciesResolved = dependenciesResolved; } /// @@ -53,23 +60,44 @@ internal MethodContainer(Container container) /// 方法调用目标 /// 在方法调用目标中被调用的方法 /// - public IMethodBindData BindMethod(string method, object target, string call) + public IMethodBind BindMethod(string method, object target, MethodInfo call) { Guard.NotEmptyOrNull(method, "method"); Guard.Requires(target != null); - Guard.NotEmptyOrNull(call, "call"); + Guard.Requires(call != null); return null; } /// - /// 生成对象中被调用方法的方法信息 + /// 调用方法 /// - /// 方法调用目标 - /// 在方法调用目标中被调用的方法 - private MethodInfo MakeMethodInfo(object target, string call) + /// 方法名 + /// 用户传入的参数 + /// 方法调用结果 + public object Invoke(string method, params object[] userParams) + { + Guard.NotEmptyOrNull(method, "method"); + MethodBind methodBind; + + if (!methodMappings.TryGetValue(method, out methodBind)) + { + throw MakeMethodNotFoundException(method); + } + + var injectParams = methodBind.ParameterInfos.Length > 0 + ? dependenciesResolved(methodBind, methodBind.ParameterInfos, userParams) + : new object[] { }; + + return methodBind.MethodInfo.Invoke(methodBind.Target, injectParams); + } + + /// + /// 生成一个方法没有找到异常 + /// + /// + private RuntimeException MakeMethodNotFoundException(string method) { - return target.GetType().GetMethod(call, - BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy); + return new RuntimeException("Method [" + method + "] is not found."); } } } From 4250a96e688bbf3552152756c2fa90d327811355 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Fri, 8 Dec 2017 18:30:36 +0800 Subject: [PATCH 38/91] container optimization --- .../Support/Container/Container.cs | 40 +++++-------------- .../Support/Container/MethodBind.cs | 36 +++-------------- .../Support/Container/MethodContainer.cs | 12 +++++- 3 files changed, 27 insertions(+), 61 deletions(-) diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 6c7e61f..541af5c 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -195,7 +195,6 @@ public IBindData GetBind(string service) Guard.NotEmptyOrNull(service, "service"); lock (syncRoot) { - service = FormatService(service); service = AliasToService(service); BindData bindData; return binds.TryGetValue(service, out bindData) ? bindData : null; @@ -222,7 +221,6 @@ public bool HasInstance(string service) Guard.NotEmptyOrNull(service, "service"); lock (syncRoot) { - service = FormatService(service); service = AliasToService(service); return instances.ContainsKey(service); } @@ -238,7 +236,6 @@ public bool IsResolved(string service) Guard.NotEmptyOrNull(service, "service"); lock (syncRoot) { - service = FormatService(service); service = AliasToService(service); return resolved.ContainsKey(service) || instances.ContainsKey(service); } @@ -254,7 +251,6 @@ public bool CanMake(string service) Guard.NotEmptyOrNull(service, "service"); lock (syncRoot) { - service = FormatService(service); service = AliasToService(service); return HasBind(service) || GetServiceType(service) != null; } @@ -500,7 +496,6 @@ public void Instance(string service, object instance) Guard.NotEmptyOrNull(service, "service"); lock (syncRoot) { - service = FormatService(service); service = AliasToService(service); var bindData = GetBind(service); @@ -540,7 +535,6 @@ public void Release(string service) Guard.NotEmptyOrNull(service, "service"); lock (syncRoot) { - service = FormatService(service); service = AliasToService(service); object instance; @@ -581,6 +575,7 @@ public void Flush() buildStack.Clear(); userParamsStack.Clear(); rebound.Clear(); + methodContainer.Flush(); } } @@ -641,7 +636,6 @@ public IContainer OnRebound(string service, Action callback) Guard.NotNull(callback, "callback"); lock (syncRoot) { - service = FormatService(service); service = AliasToService(service); List> list; @@ -680,7 +674,6 @@ public void Unbind(string service) { lock (syncRoot) { - service = FormatService(service); service = AliasToService(service); Release(service); @@ -1085,7 +1078,7 @@ protected virtual void AttributeInject(Bindable makeServiceBindData, object make /// 输入的构造参数列表 /// 服务所需参数的解决结果 /// 生成的实例类型和需求类型不一致 - protected virtual object[] GetDependencies(Bindable makeServiceBindData, IList baseParams, object[] userParams) + protected virtual object[] GetDependencies(Bindable makeServiceBindData, ParameterInfo[] baseParams, object[] userParams) { var results = new List(); @@ -1128,6 +1121,7 @@ protected virtual object[] GetDependencies(Bindable makeServiceBindData, IList

最终映射的服务名 protected virtual string AliasToService(string service) { + service = FormatService(service); string alias; return aliases.TryGetValue(service, out alias) ? alias : service; } @@ -1245,7 +1239,6 @@ private object Resolve(string service, params object[] userParams) Guard.NotEmptyOrNull(service, "service"); lock (syncRoot) { - service = FormatService(service); service = AliasToService(service); object instance; @@ -1313,16 +1306,14 @@ private object Build(string makeService, Type makeServiceType, bool isFromMake, } ///

- /// 构造服务实现 + /// 预构造服务实现(准备需要注入的参数) /// /// 服务绑定数据 /// 服务类型 /// 用户传入的构造参数 /// 服务实例 - private object CreateInstance(BindData makeServiceBindData, Type makeServiceType, object[] userParams) + private object CreateInstance(Bindable makeServiceBindData, Type makeServiceType, object[] userParams) { - userParams = userParams ?? new object[] { }; - if (makeServiceType == null || makeServiceType.IsAbstract || makeServiceType.IsInterface) @@ -1331,23 +1322,14 @@ private object CreateInstance(BindData makeServiceBindData, Type makeServiceType } var constructor = makeServiceType.GetConstructors(); - if (constructor.Length <= 0) + if (constructor.Length > 0) { - try - { - return Activator.CreateInstance(makeServiceType); - } - catch (Exception ex) - { - throw MakeBuildFaildException(makeServiceBindData.Service, makeServiceType, ex); - } + var parameter = constructor[constructor.Length - 1].GetParameters(); + userParams = parameter.Length > 0 ? GetDependencies(makeServiceBindData, parameter, userParams) : null; } - - var parameter = new List(constructor[constructor.Length - 1].GetParameters()); - - if (parameter.Count > 0) + else { - userParams = GetDependencies(makeServiceBindData, parameter, userParams); + userParams = null; } try @@ -1367,7 +1349,7 @@ private object CreateInstance(BindData makeServiceBindData, Type makeServiceType /// 服务类型 /// 构造参数 /// 服务实例 - private object BuildUseConcrete(BindData makeServiceBindData, Type makeServiceType, object[] param) + private object BuildUseConcrete(IBindData makeServiceBindData, Type makeServiceType, object[] param) { return makeServiceBindData.Concrete != null ? makeServiceBindData.Concrete(this, param) : diff --git a/src/CatLib.Core/Support/Container/MethodBind.cs b/src/CatLib.Core/Support/Container/MethodBind.cs index b73d52a..474d8a4 100644 --- a/src/CatLib.Core/Support/Container/MethodBind.cs +++ b/src/CatLib.Core/Support/Container/MethodBind.cs @@ -21,41 +21,17 @@ internal sealed class MethodBind : Bindable , IMethodBind /// /// 方法信息 /// - private readonly MethodInfo methodInfo; - - /// - /// 方法信息 - /// - public MethodInfo MethodInfo - { - get { return methodInfo; } - } - - /// - /// 调用目标 - /// - private readonly object target; + public MethodInfo MethodInfo { get; private set; } /// /// 调用目标 /// - public object Target - { - get { return target; } - } + public object Target { get; private set; } /// /// 参数表 /// - private readonly ParameterInfo[] parameterInfos; - - /// - /// 参数表 - /// - public ParameterInfo[] ParameterInfos - { - get { return parameterInfos; } - } + public ParameterInfo[] ParameterInfos { get; private set; } /// /// 构建一个绑定数据 @@ -67,9 +43,9 @@ public ParameterInfo[] ParameterInfos public MethodBind(Container container, string service, object target, MethodInfo call) :base(container, service) { - this.target = target; - methodInfo = call; - parameterInfos = methodInfo.GetParameters(); + Target = target; + MethodInfo = call; + ParameterInfos = call.GetParameters(); } /// diff --git a/src/CatLib.Core/Support/Container/MethodContainer.cs b/src/CatLib.Core/Support/Container/MethodContainer.cs index e566526..823278c 100644 --- a/src/CatLib.Core/Support/Container/MethodContainer.cs +++ b/src/CatLib.Core/Support/Container/MethodContainer.cs @@ -38,14 +38,14 @@ internal sealed class MethodContainer /// /// 依赖解决器 /// - private readonly Func, object[], object[]> dependenciesResolved; + private readonly Func dependenciesResolved; /// /// 构建一个新的方法容器 /// /// /// 依赖解决器 - internal MethodContainer(Container container, Func, object[], object[]> dependenciesResolved) + internal MethodContainer(Container container, Func dependenciesResolved) { this.container = container; targetToMethodsMappings = new Dictionary>(); @@ -91,6 +91,14 @@ public object Invoke(string method, params object[] userParams) return methodBind.MethodInfo.Invoke(methodBind.Target, injectParams); } + /// + /// 清空容器的所有实例,绑定,别名,标签,解决器 + /// + public void Flush() + { + + } + /// /// 生成一个方法没有找到异常 /// From 3d66deba42eaef5ad42eac3019a52f36d3cbd549 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Fri, 8 Dec 2017 18:59:18 +0800 Subject: [PATCH 39/91] container optimization --- .../Support/Container/ContainerTests.cs | 2 +- src/CatLib.Core/CatLib/App.cs | 4 +- .../Support/Container/Container.cs | 73 +++++++++---------- .../Support/Container/ContainerExtend.cs | 4 +- .../Support/Container/IContainer.cs | 2 +- 5 files changed, 42 insertions(+), 43 deletions(-) diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs index d8f2150..ac7aa35 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs @@ -1076,7 +1076,7 @@ public TestOptionalPrimitiveClass(int value = 100) public class SupportNullContainer : Container { - protected override void GuardResolveInstance(object instance, string makeService, Type makeServiceType) + protected override void GuardResolveInstance(object instance, string makeService) { } diff --git a/src/CatLib.Core/CatLib/App.cs b/src/CatLib.Core/CatLib/App.cs index 94c1e45..958877c 100644 --- a/src/CatLib.Core/CatLib/App.cs +++ b/src/CatLib.Core/CatLib/App.cs @@ -303,9 +303,9 @@ public static object[] Tagged(string tag) /// /// 服务名或者别名 /// 服务实例 - public static void Instance(string service, object instance) + public static object Instance(string service, object instance) { - Handler.Instance(service, instance); + return Handler.Instance(service, instance); } /// diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 541af5c..37a46a1 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -369,7 +369,7 @@ public IBindData Bind(string service, Type concrete, bool isStatic) return Bind(service, (c, param) => { var container = (Container)c; - return container.Build(service, concrete, false, param); + return container.Build(GetBindFillable(service), concrete, false, param); }, isStatic); } @@ -491,7 +491,8 @@ public Func Factory(string service) /// 服务实例,null也是合法的实例值 /// null或者空字符串 /// 的服务在绑定设置中不是静态的 - public void Instance(string service, object instance) + /// 被修饰器处理后的新的实例 + public object Instance(string service, object instance) { Guard.NotEmptyOrNull(service, "service"); lock (syncRoot) @@ -523,6 +524,8 @@ public void Instance(string service, object instance) { TriggerOnRebound(service); } + + return instance; } } @@ -991,12 +994,11 @@ protected virtual void GuardUserParamsCount(int count) /// /// 服务实例 /// 服务名 - /// 服务类型 - protected virtual void GuardResolveInstance(object instance, string makeService, Type makeServiceType) + protected virtual void GuardResolveInstance(object instance, string makeService) { if (instance == null) { - throw MakeBuildFaildException(makeService, makeServiceType, null); + throw MakeBuildFaildException(makeService, GetServiceType(makeService), null); } } @@ -1256,7 +1258,8 @@ private object Resolve(string service, params object[] userParams) userParamsStack.Push(userParams); try { - return Build(service, null, true, userParams); + var bindData = GetBindFillable(service); + return Inject(bindData, Build(bindData, null, true, userParams)); } finally { @@ -1267,42 +1270,38 @@ private object Resolve(string service, params object[] userParams) } /// - /// 编译服务 + /// 为对象进行依赖注入 /// - /// 服务名 - /// 服务类型 - /// 是否直接调用自Make函数 - /// 用户传入的构造参数 - /// 服务实例 - private object Build(string makeService, Type makeServiceType, bool isFromMake, params object[] userParams) + /// 绑定数据 + /// 对象实例 + /// 注入完成的对象 + private object Inject(BindData bindData, object instance) { - var bindData = GetBindFillable(makeService); - var buildInstance = isFromMake ? BuildUseConcrete(bindData, makeServiceType, userParams) - : CreateInstance(bindData, makeServiceType ?? (makeServiceType = GetServiceType(bindData.Service)), userParams); - - // 只有是来自于make函数的调用时才执行di,包装,以及修饰 - // 不要在这个之前执行任何调用否则在返回时这些调用会再次被执行 - if (!isFromMake) - { - return buildInstance; - } + GuardResolveInstance(instance, bindData.Service); - GuardResolveInstance(buildInstance, makeService, makeServiceType); + AttributeInject(bindData, instance); - AttributeInject(bindData, buildInstance); + instance = bindData.IsStatic + ? Instance(bindData.Service, instance) + : TriggerOnResolving(bindData, bindData.TriggerResolving(instance)); - if (bindData.IsStatic) - { - Instance(makeService, buildInstance); - } - else - { - buildInstance = TriggerOnResolving(bindData, bindData.TriggerResolving(buildInstance)); - } + resolved[bindData.Service] = true; - resolved[makeService] = true; + return instance; + } - return buildInstance; + /// + /// 编译服务 + /// + /// 服务绑定数据 + /// 服务类型 + /// 是否是被Resolve函数调用的 + /// 用户传入的构造参数 + /// 服务实例 + private object Build(BindData bindData, Type makeServiceType, bool isFromResolve, params object[] userParams) + { + return isFromResolve ? BuildUseConcrete(bindData, makeServiceType, userParams) + : CreateInstance(bindData, makeServiceType ?? GetServiceType(bindData.Service), userParams); } /// @@ -1349,11 +1348,11 @@ private object CreateInstance(Bindable makeServiceBindData, Type makeServiceType /// 服务类型 /// 构造参数 /// 服务实例 - private object BuildUseConcrete(IBindData makeServiceBindData, Type makeServiceType, object[] param) + private object BuildUseConcrete(BindData makeServiceBindData, Type makeServiceType, object[] param) { return makeServiceBindData.Concrete != null ? makeServiceBindData.Concrete(this, param) : - Build(makeServiceBindData.Service, makeServiceType, false, param); + Build(makeServiceBindData, makeServiceType, false, param); } /// diff --git a/src/CatLib.Core/Support/Container/ContainerExtend.cs b/src/CatLib.Core/Support/Container/ContainerExtend.cs index 72a2a1d..3571670 100644 --- a/src/CatLib.Core/Support/Container/ContainerExtend.cs +++ b/src/CatLib.Core/Support/Container/ContainerExtend.cs @@ -428,9 +428,9 @@ public static void Release(this IContainer container) /// 服务名 /// 服务容器 /// 实例值 - public static void Instance(this IContainer container, object instance) + public static object Instance(this IContainer container, object instance) { - container.Instance(container.Type2Service(typeof(TService)), instance); + return container.Instance(container.Type2Service(typeof(TService)), instance); } /// diff --git a/src/CatLib.Core/Support/Container/IContainer.cs b/src/CatLib.Core/Support/Container/IContainer.cs index 172a88d..32579ef 100644 --- a/src/CatLib.Core/Support/Container/IContainer.cs +++ b/src/CatLib.Core/Support/Container/IContainer.cs @@ -111,7 +111,7 @@ public interface IContainer /// /// 服务名或者别名 /// 服务实例 - void Instance(string service, object instance); + object Instance(string service, object instance); /// /// 释放某个静态化实例 From f0cd46ca2d6130f52543c8d7061112c86da7fdf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Sat, 9 Dec 2017 16:45:20 +0800 Subject: [PATCH 40/91] container optimization --- .../Support/Container/ContainerTests.cs | 2 +- .../Support/Container/Container.cs | 58 ++++++++++--------- 2 files changed, 31 insertions(+), 29 deletions(-) diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs index ac7aa35..3d64d69 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs @@ -770,7 +770,7 @@ public void MakeNoBindType() { var container = MakeContainer(); - //container.OnFindType(Type.GetServiceType); 不要使用这种写法否则域将不是这个程序集 + //container.OnFindType(Type.GetType); 不要使用这种写法否则域将不是这个程序集 container.OnFindType((str) => { return Type.GetType(str); diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 37a46a1..2251ba3 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -96,16 +96,32 @@ public class Container : IContainer /// private readonly Stack buildStack; + /// + /// 编译堆栈 + /// + protected Stack BuildStack + { + get { return buildStack; } + } + /// /// 用户参数堆栈 /// private readonly Stack userParamsStack; + /// + /// 用户参数堆栈 + /// + protected Stack UserParamsStack + { + get { return userParamsStack; } + } + /// /// 构造一个容器 /// /// 初始预计服务数量 - public Container(int prime = 32) + public Container(int prime = 64) { prime = Math.Max(8, prime); tags = new Dictionary>((int)(prime * 0.25)); @@ -252,7 +268,7 @@ public bool CanMake(string service) lock (syncRoot) { service = AliasToService(service); - return HasBind(service) || GetServiceType(service) != null; + return HasBind(service) || SpeculatedServiceType(service) != null; } } @@ -369,7 +385,7 @@ public IBindData Bind(string service, Type concrete, bool isStatic) return Bind(service, (c, param) => { var container = (Container)c; - return container.Build(GetBindFillable(service), concrete, false, param); + return container.CreateInstance(GetBindFillable(service), concrete, param); }, isStatic); } @@ -998,16 +1014,16 @@ protected virtual void GuardResolveInstance(object instance, string makeService) { if (instance == null) { - throw MakeBuildFaildException(makeService, GetServiceType(makeService), null); + throw MakeBuildFaildException(makeService, SpeculatedServiceType(makeService), null); } } /// - /// 获取通过服务名获取服务的类型 + /// 根据服务名推测服务的类型 /// /// 服务名 /// 服务类型 - protected virtual Type GetServiceType(string service) + protected virtual Type SpeculatedServiceType(string service) { Type result; @@ -1259,7 +1275,7 @@ private object Resolve(string service, params object[] userParams) try { var bindData = GetBindFillable(service); - return Inject(bindData, Build(bindData, null, true, userParams)); + return Inject(bindData, Build(bindData, userParams)); } finally { @@ -1293,19 +1309,19 @@ private object Inject(BindData bindData, object instance) /// /// 编译服务 /// - /// 服务绑定数据 - /// 服务类型 - /// 是否是被Resolve函数调用的 + /// 服务绑定数据 /// 用户传入的构造参数 /// 服务实例 - private object Build(BindData bindData, Type makeServiceType, bool isFromResolve, params object[] userParams) + private object Build(BindData makeServiceBindData, object[] userParams) { - return isFromResolve ? BuildUseConcrete(bindData, makeServiceType, userParams) - : CreateInstance(bindData, makeServiceType ?? GetServiceType(bindData.Service), userParams); + return makeServiceBindData.Concrete != null + ? makeServiceBindData.Concrete(this, userParams) + : CreateInstance(makeServiceBindData, SpeculatedServiceType(makeServiceBindData.Service), + userParams); } /// - /// 预构造服务实现(准备需要注入的参数) + /// 构造服务实现(准备需要注入的参数) /// /// 服务绑定数据 /// 服务类型 @@ -1341,20 +1357,6 @@ private object CreateInstance(Bindable makeServiceBindData, Type makeServiceType } } - /// - /// 常规编译一个服务 - /// - /// 服务绑定数据 - /// 服务类型 - /// 构造参数 - /// 服务实例 - private object BuildUseConcrete(BindData makeServiceBindData, Type makeServiceType, object[] param) - { - return makeServiceBindData.Concrete != null ? - makeServiceBindData.Concrete(this, param) : - Build(makeServiceBindData, makeServiceType, false, param); - } - /// /// 获取服务绑定数据,如果数据为null则填充数据 /// From 37e01ba24414abc093ec9c74b9445a1dd8527783 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Sat, 9 Dec 2017 17:00:40 +0800 Subject: [PATCH 41/91] sync App interface --- src/CatLib.Core/CatLib/App.cs | 47 ++++++++++++++++++- .../Support/Container/Container.cs | 3 +- .../Support/Container/GivenData.cs | 2 +- .../Support/Container/IContainer.cs | 3 +- 4 files changed, 50 insertions(+), 5 deletions(-) diff --git a/src/CatLib.Core/CatLib/App.cs b/src/CatLib.Core/CatLib/App.cs index 958877c..55e3649 100644 --- a/src/CatLib.Core/CatLib/App.cs +++ b/src/CatLib.Core/CatLib/App.cs @@ -218,6 +218,16 @@ public static bool HasBind(string service) return Handler.HasBind(service); } + /// + /// 是否可以生成服务 + /// + /// 服务名或者别名 + /// 是否可以生成服务 + public static bool CanMake(string service) + { + return Handler.CanMake(service); + } + /// /// 服务是否是静态化的,如果服务不存在也将返回false /// @@ -228,6 +238,16 @@ public static bool IsStatic(string service) return Handler.IsStatic(service); } + /// + /// 是否是别名 + /// + /// 名字 + /// 是否是别名 + public bool IsAlias(string name) + { + return Handler.IsAlias(name); + } + /// /// 绑定一个服务 /// @@ -504,6 +524,30 @@ public static IContainer OnFindType(Func func, int priority = int. return Handler.OnFindType(func, priority); } + /// + /// 当一个已经被解决的服务,发生重定义时触发 + /// + /// 服务名 + /// 回调 + /// 服务容器 + public static IContainer OnRebound(string service, Action callback) + { + return Handler.OnRebound(service, callback); + } + + /// + /// 关注指定的服务,当服务触发重定义时调用指定对象的指定方法 + /// 调用是以依赖注入的形式进行的 + /// 服务的新建(第一次解决服务)操作并不会触发重定义 + /// + /// 关注的服务名 + /// 当服务发生重定义时调用的目标 + /// 方法信息 + public static void Watch(string service, object target, MethodInfo methodInfo) + { + Handler.Watch(service, target, methodInfo); + } + /// /// 类型转为服务名 /// @@ -642,8 +686,7 @@ public static IBindData Bind(Func concre /// 服务名 /// 服务实现 /// 服务绑定数据 - public static IBindData Bind(string service, - Func concrete) + public static IBindData Bind(string service, Func concrete) { return Handler.Bind(service, concrete); } diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 2251ba3..424318c 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -669,7 +669,8 @@ public IContainer OnRebound(string service, Action callback) /// /// 关注指定的服务,当服务触发重定义时调用指定对象的指定方法 - /// 调用是以依赖注入的形式进行的 + /// 调用是以依赖注入的形式进行的 + /// 服务的新建(第一次解决服务)操作并不会触发重定义 /// /// 关注的服务名 /// 当服务发生重定义时调用的目标 diff --git a/src/CatLib.Core/Support/Container/GivenData.cs b/src/CatLib.Core/Support/Container/GivenData.cs index a2dcbe4..b842305 100644 --- a/src/CatLib.Core/Support/Container/GivenData.cs +++ b/src/CatLib.Core/Support/Container/GivenData.cs @@ -60,7 +60,7 @@ internal IGivenData Needs(string needs) /// 服务绑定数据 public TReturn Given(string service) { - Guard.NotEmptyOrNull(service , "service"); + Guard.NotEmptyOrNull(service, "service"); bindable.AddContextual(needs, service); return bindable as TReturn; } diff --git a/src/CatLib.Core/Support/Container/IContainer.cs b/src/CatLib.Core/Support/Container/IContainer.cs index 32579ef..a0dbb0d 100644 --- a/src/CatLib.Core/Support/Container/IContainer.cs +++ b/src/CatLib.Core/Support/Container/IContainer.cs @@ -194,7 +194,8 @@ public interface IContainer /// /// 关注指定的服务,当服务触发重定义时调用指定对象的指定方法 - /// 调用是以依赖注入的形式进行的 + /// 调用是以依赖注入的形式进行的 + /// 服务的新建(第一次解决服务)操作并不会触发重定义 /// /// 关注的服务名 /// 当服务发生重定义时调用的目标 From e2140a40e3cc1fe452e4809d7eda9b8a4549471d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Sat, 9 Dec 2017 17:02:55 +0800 Subject: [PATCH 42/91] change to static class --- src/CatLib.Core/CatLib/App.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CatLib.Core/CatLib/App.cs b/src/CatLib.Core/CatLib/App.cs index 55e3649..c330a82 100644 --- a/src/CatLib.Core/CatLib/App.cs +++ b/src/CatLib.Core/CatLib/App.cs @@ -18,7 +18,7 @@ namespace CatLib /// CatLib实例 /// [ExcludeFromCodeCoverage] - public sealed class App + public static class App { /// /// 当新建Application时 @@ -243,7 +243,7 @@ public static bool IsStatic(string service) /// /// 名字 /// 是否是别名 - public bool IsAlias(string name) + public static bool IsAlias(string name) { return Handler.IsAlias(name); } From be1ed0923ada4779926c6fbbb0ae318df09ba467 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Sat, 9 Dec 2017 17:51:49 +0800 Subject: [PATCH 43/91] add unit test --- .../CatLib/ApplicationTests.cs | 7 +++ .../Support/Container/ContainerHelperTests.cs | 2 + .../Support/Container/ContainerTests.cs | 50 +++++++++++++++++++ src/CatLib.Core/CatLib/App.cs | 8 +-- src/CatLib.Core/CatLib/Application.cs | 16 ++++-- src/CatLib.Core/CatLib/IApplication.cs | 5 +- 6 files changed, 76 insertions(+), 12 deletions(-) diff --git a/src/CatLib.Core.Tests/CatLib/ApplicationTests.cs b/src/CatLib.Core.Tests/CatLib/ApplicationTests.cs index 6be7681..56185ed 100644 --- a/src/CatLib.Core.Tests/CatLib/ApplicationTests.cs +++ b/src/CatLib.Core.Tests/CatLib/ApplicationTests.cs @@ -145,6 +145,13 @@ public void GetCurrentProcess() Assert.AreEqual(Application.StartProcess.Inited, app.Process); } + [TestMethod] + public void TestDebugLevel() + { + App.DebugLevel = DebugLevels.Dev; + Assert.AreEqual(DebugLevels.Dev, App.DebugLevel); + } + /// /// 重复的引导测试 /// diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerHelperTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerHelperTests.cs index 779405b..160daee 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerHelperTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerHelperTests.cs @@ -136,6 +136,7 @@ public void TestBindIf() Assert.AreEqual(true, App.BindIf((c, p) => 100, out bindData)); Assert.AreEqual(true, App.BindIf(out bindData)); + Assert.AreEqual(false, App.BindIf(out bindData)); Assert.AreEqual(typeof(double), App.Make(App.Type2Service(typeof(float))).GetType()); } @@ -159,6 +160,7 @@ public void TestSingletonIf() Assert.AreEqual(true, App.SingletonIf((c, p) => 100, out bindData)); Assert.AreEqual(true, App.SingletonIf(out bindData)); + Assert.AreEqual(false, App.SingletonIf(out bindData)); Assert.AreEqual(typeof(double), App.Make(App.Type2Service(typeof(float))).GetType()); } diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs index 3d64d69..4faa8d9 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs @@ -1076,6 +1076,16 @@ public TestOptionalPrimitiveClass(int value = 100) public class SupportNullContainer : Container { + public string[] GetStack() + { + return BuildStack.ToArray(); + } + + public object[][] GetUserParams() + { + return UserParamsStack.ToArray(); + } + protected override void GuardResolveInstance(object instance, string makeService) { @@ -1091,6 +1101,24 @@ public void TestSupportNullValueContainer() Assert.AreEqual(null, container.Make("null")); } + [TestMethod] + public void TestGetStack() + { + var container = new SupportNullContainer(); + container.Bind("null", (c, p) => + { + Assert.AreEqual(1, container.GetStack().Length); + Assert.AreEqual(1, container.GetUserParams().Length); + Assert.AreEqual(3, container.GetUserParams()[0].Length); + return null; + }); + + Assert.AreEqual(null, container.Make("null", "123", "hello", 12333)); + + Assert.AreEqual(0, container.GetStack().Length); + Assert.AreEqual(0, container.GetUserParams().Length); + } + public class TestInjectNullClass { public TestInjectNullClass(TestMakeBasePrimitiveConstructor cls) @@ -1730,6 +1758,28 @@ public void TestWatch() Assert.AreEqual(200, cls.value); Assert.AreSame(container, cls.container); } + + [TestMethod] + public void TestOccupiedKeyInstance() + { + var container = new Container(); + container.Instance(null); + var cls = new TestWatchCLass(); + container.Watch("WatchService", cls, "OnChange"); + container.Instance("WatchService", 100); + + var isThrow = false; + try + { + container.Instance("WatchService", 200); + } + catch (RuntimeException) + { + isThrow = true; + } + + Assert.AreEqual(true, isThrow); + } #endregion /// diff --git a/src/CatLib.Core/CatLib/App.cs b/src/CatLib.Core/CatLib/App.cs index c330a82..ecaf993 100644 --- a/src/CatLib.Core/CatLib/App.cs +++ b/src/CatLib.Core/CatLib/App.cs @@ -144,12 +144,12 @@ public static int GetPriority(Type type, string method = null) } /// - /// 设定调试等级 + /// 调试等级 /// - /// 调试等级 - public static void SetDebugLevel(DebugLevels level) + public static DebugLevels DebugLevel { - Handler.SetDebugLevel(level); + get { return Handler.DebugLevel; } + set { Handler.DebugLevel = value; } } /// diff --git a/src/CatLib.Core/CatLib/Application.cs b/src/CatLib.Core/CatLib/Application.cs index 165a2ae..9a2ef16 100644 --- a/src/CatLib.Core/CatLib/Application.cs +++ b/src/CatLib.Core/CatLib/Application.cs @@ -139,7 +139,7 @@ public Application() RegisterCoreAlias(); RegisterCoreService(); OnFindType(finder => { return Type.GetType(finder); }); - SetDebugLevel(DebugLevels.Prod); + DebugLevel = DebugLevels.Prod; } /// @@ -266,12 +266,18 @@ public int GetPriority(Type type, string method = null) } /// - /// 设定调试等级 + /// 调试等级 /// - /// 调试等级 - public void SetDebugLevel(DebugLevels level) + public DebugLevels DebugLevel { - Instance(Type2Service(typeof(DebugLevels)), level); + get + { + return (DebugLevels)Make(Type2Service(typeof(DebugLevels))); + } + set + { + Instance(Type2Service(typeof(DebugLevels)), value); + } } /// diff --git a/src/CatLib.Core/CatLib/IApplication.cs b/src/CatLib.Core/CatLib/IApplication.cs index a92b118..24e9626 100644 --- a/src/CatLib.Core/CatLib/IApplication.cs +++ b/src/CatLib.Core/CatLib/IApplication.cs @@ -79,9 +79,8 @@ public interface IApplication : IContainer, IDispatcher int GetPriority(Type type, string method = null); /// - /// 设定调试等级 + /// 调试等级 /// - /// 调试等级 - void SetDebugLevel(DebugLevels level); + DebugLevels DebugLevel { get; set; } } } From 824f7ce26ff5d61c3f3a1e1fd5aed4d5529d4aca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Sun, 10 Dec 2017 12:37:39 +0800 Subject: [PATCH 44/91] method container update --- .../Support/Container/Container.cs | 72 ++++++++--- .../Support/Container/MethodBind.cs | 1 + .../Support/Container/MethodContainer.cs | 120 ++++++++++++++++-- 3 files changed, 159 insertions(+), 34 deletions(-) diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 424318c..05e8d96 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -432,6 +432,43 @@ public IBindData Bind(string service, Func concret } } + /// + /// 绑定一个方法到容器 + /// + /// 方法名 + /// 调用目标 + /// 调用方法 + /// 方法绑定数据 + public IMethodBind BindMethod(string method, object target, MethodInfo call) + { + return methodContainer.Bind(method, target, call); + } + + /// + /// 解除绑定的方法 + /// + /// + /// 解除目标 + /// 如果为字符串则作为调用方法名 + /// 如果为IMethodBind则作为指定方法 + /// 如果为其他对象则作为调用目标做全体解除 + /// + public void UnbindMethod(object target) + { + methodContainer.Unbind(target); + } + + /// + /// 调用一个已经被绑定的方法 + /// + /// 方法名 + /// 用户提供的参数 + /// 调用结果 + public object Invoke(string method, params object[] userParams) + { + return methodContainer.Invoke(method, userParams); + } + /// /// 以依赖注入形式调用一个方法 /// @@ -456,17 +493,6 @@ public object Call(object target, MethodInfo methodInfo, params object[] userPar } } - /// - /// 调用一个已经被绑定的方法 - /// - /// 方法名 - /// 用户提供的参数 - /// 调用结果 - public object Invoke(string method, params object[] userParams) - { - return methodContainer.Invoke(method, userParams); - } - /// /// 构造服务 /// @@ -801,17 +827,21 @@ protected virtual string GetPropertyNeedsService(PropertyInfo property) protected virtual string GetParamNeedsService(ParameterInfo baseParam) { var needService = Type2Service(baseParam.ParameterType); - if (baseParam.IsDefined(injectTarget, false)) + if (!baseParam.IsDefined(injectTarget, false)) { - var propertyAttrs = baseParam.GetCustomAttributes(injectTarget, false); - if (propertyAttrs.Length > 0) - { - var injectAttr = (InjectAttribute)propertyAttrs[0]; - if (!string.IsNullOrEmpty(injectAttr.Alias)) - { - needService = injectAttr.Alias; - } - } + return needService; + } + + var propertyAttrs = baseParam.GetCustomAttributes(injectTarget, false); + if (propertyAttrs.Length <= 0) + { + return needService; + } + + var injectAttr = (InjectAttribute)propertyAttrs[0]; + if (!string.IsNullOrEmpty(injectAttr.Alias)) + { + needService = injectAttr.Alias; } return needService; } diff --git a/src/CatLib.Core/Support/Container/MethodBind.cs b/src/CatLib.Core/Support/Container/MethodBind.cs index 474d8a4..69b7b64 100644 --- a/src/CatLib.Core/Support/Container/MethodBind.cs +++ b/src/CatLib.Core/Support/Container/MethodBind.cs @@ -53,6 +53,7 @@ public MethodBind(Container container, string service, object target, MethodInfo /// protected override void ReleaseBind() { + Container.UnbindMethod(this); } } } diff --git a/src/CatLib.Core/Support/Container/MethodContainer.cs b/src/CatLib.Core/Support/Container/MethodContainer.cs index 823278c..9ccb263 100644 --- a/src/CatLib.Core/Support/Container/MethodContainer.cs +++ b/src/CatLib.Core/Support/Container/MethodContainer.cs @@ -23,23 +23,28 @@ internal sealed class MethodContainer /// /// 调用方法目标 映射到 方法名字 /// - private Dictionary> targetToMethodsMappings; + private readonly Dictionary> targetToMethodsMappings; /// /// 绑定数据 /// - private Dictionary methodMappings; + private readonly Dictionary methodMappings; /// /// 依赖注入容器 /// - private Container container; + private readonly Container container; /// /// 依赖解决器 /// private readonly Func dependenciesResolved; + /// + /// 同步锁 + /// + private readonly object syncRoot; + /// /// 构建一个新的方法容器 /// @@ -51,6 +56,7 @@ internal MethodContainer(Container container, Func>(); methodMappings = new Dictionary(); this.dependenciesResolved = dependenciesResolved; + syncRoot = new object(); } /// @@ -60,12 +66,32 @@ internal MethodContainer(Container container, Func方法调用目标 /// 在方法调用目标中被调用的方法 /// - public IMethodBind BindMethod(string method, object target, MethodInfo call) + public IMethodBind Bind(string method, object target, MethodInfo call) { Guard.NotEmptyOrNull(method, "method"); Guard.Requires(target != null); Guard.Requires(call != null); - return null; + + lock (syncRoot) + { + if (methodMappings.ContainsKey(method)) + { + throw new RuntimeException("Method [" + method + "] is already bind"); + } + + List targetMappings; + if (!targetToMethodsMappings.TryGetValue(target, out targetMappings)) + { + targetToMethodsMappings[target] = targetMappings = new List(); + } + + var methodBind = new MethodBind(container, method, target, call); + + methodMappings[method] = methodBind; + targetMappings.Add(method); + + return null; + } } /// @@ -77,18 +103,82 @@ public IMethodBind BindMethod(string method, object target, MethodInfo call) public object Invoke(string method, params object[] userParams) { Guard.NotEmptyOrNull(method, "method"); - MethodBind methodBind; - if (!methodMappings.TryGetValue(method, out methodBind)) + lock (syncRoot) { - throw MakeMethodNotFoundException(method); + MethodBind methodBind; + if (!methodMappings.TryGetValue(method, out methodBind)) + { + throw MakeMethodNotFoundException(method); + } + + var injectParams = methodBind.ParameterInfos.Length > 0 + ? dependenciesResolved(methodBind, methodBind.ParameterInfos, userParams) + : new object[] { }; + + return methodBind.MethodInfo.Invoke(methodBind.Target, injectParams); } + } + + /// + /// 解除绑定 + /// + /// + /// 解除目标 + /// 如果为字符串则作为调用方法名 + /// 如果为IMethodBind则作为指定方法 + /// 如果为其他对象则作为调用目标做全体解除 + /// + public void Unbind(object target) + { + Guard.Requires(target != null); - var injectParams = methodBind.ParameterInfos.Length > 0 - ? dependenciesResolved(methodBind, methodBind.ParameterInfos, userParams) - : new object[] { }; + lock (syncRoot) + { + var methodBind = target as MethodBind; + if (methodBind != null || + (target is string && methodMappings.TryGetValue(target.ToString(), out methodBind))) + { + UnbindWithMethodBind(methodBind); + return; + } - return methodBind.MethodInfo.Invoke(methodBind.Target, injectParams); + UnbindWithObject(target); + } + } + + /// + /// 根据方法绑定信息解除绑定 + /// + /// 方法绑定信息 + private void UnbindWithMethodBind(MethodBind methodBind) + { + methodMappings.Remove(methodBind.Service); + + List methods; + if (targetToMethodsMappings.TryGetValue(methodBind.Target, out methods)) + { + methods.Remove(methodBind.Service); + } + } + + /// + /// 根据对象绑定移除为该对象绑定的所有方法 + /// + /// 对象信息 + private void UnbindWithObject(object target) + { + List methods; + if (!targetToMethodsMappings.TryGetValue(target, out methods)) + { + return; + } + + targetToMethodsMappings.Remove(target); + foreach (var method in methods) + { + methodMappings.Remove(method); + } } /// @@ -96,7 +186,11 @@ public object Invoke(string method, params object[] userParams) /// public void Flush() { - + lock (syncRoot) + { + targetToMethodsMappings.Clear(); + methodMappings.Clear(); + } } /// From 1d90eddcc6d4efca3dbc8c4f9ba4b7f3c92a759c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Sun, 10 Dec 2017 12:52:49 +0800 Subject: [PATCH 45/91] container add flash function --- .../Support/Container/Container.cs | 73 ++++++++++++------- 1 file changed, 45 insertions(+), 28 deletions(-) diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 05e8d96..77f5dfd 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -746,6 +746,50 @@ public virtual string Type2Service(Type type) return type.ToString(); } + /// + /// 在回调区间内暂时性的静态化一个服务实例 + /// + /// 回调区间 + /// 服务映射 + public void Flash(Action callback, params KeyValuePair[] services) + { + if (services.Length <= 0) + { + callback.Invoke(); + return; + } + + lock (syncRoot) + { + foreach (var service in services) + { + if (HasInstance(service.Key)) + { + throw new RuntimeException("Flash service [" + service.Key + "] is already exists."); + } + } + + var index = 0; + try + { + foreach (var service in services) + { + ++index; + Instance(service.Key, service.Value); + } + + callback.Invoke(); + } + finally + { + while (--index >= 0) + { + Release(services[index].Key); + } + } + } + } + /// /// 从用户传入的参数中获取依赖 /// @@ -1219,34 +1263,7 @@ private void TriggerOnRebound(string service) { callback(instance); } - }, Type2Service(typeof(IBindData)), bind); - } - - /// - /// 在回调区间内暂时性的静态化一个服务实例 - /// - /// 回调区间 - /// 服务名 - /// 实例 - private void Flash(Action callback, string service, object instance) - { - lock (syncRoot) - { - if (HasInstance(service)) - { - throw new RuntimeException("Flash service [" + service + "] is already exists."); - } - - try - { - Instance(service, instance); - callback.Invoke(); - } - finally - { - Release(service); - } - } + }, new KeyValuePair(Type2Service(typeof(IBindData)), bind)); } /// From 3e905d3f88330003f79ac039237356f7b0b800de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Sun, 10 Dec 2017 19:50:29 +0800 Subject: [PATCH 46/91] add method container unit test --- .../Support/Container/MethodContainerTests.cs | 28 ++++++ src/CatLib.Core/CatLib/App.cs | 95 +++++++++++++++++++ .../Support/Container/Container.cs | 41 +++----- .../Support/Container/ContainerExtend.cs | 78 +++++++++++++++ .../Support/Container/IContainer.cs | 25 +++++ src/CatLib.Core/Support/Util/Arr.cs | 38 ++++++++ 6 files changed, 275 insertions(+), 30 deletions(-) create mode 100644 src/CatLib.Core.Tests/Support/Container/MethodContainerTests.cs diff --git a/src/CatLib.Core.Tests/Support/Container/MethodContainerTests.cs b/src/CatLib.Core.Tests/Support/Container/MethodContainerTests.cs new file mode 100644 index 0000000..5304e36 --- /dev/null +++ b/src/CatLib.Core.Tests/Support/Container/MethodContainerTests.cs @@ -0,0 +1,28 @@ +/* + * 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 Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace CatLib.Core.Tests.Support.Container +{ + [TestClass] + class MethodContainerTests + { + [TestMethod] + public void TestBindMethod() + { + App.BindMethod("TestMethod", () => + { + return null; + }); + } + } +} diff --git a/src/CatLib.Core/CatLib/App.cs b/src/CatLib.Core/CatLib/App.cs index ecaf993..5c7b43e 100644 --- a/src/CatLib.Core/CatLib/App.cs +++ b/src/CatLib.Core/CatLib/App.cs @@ -10,6 +10,7 @@ */ using System; +using System.Collections.Generic; using System.Reflection; namespace CatLib @@ -346,6 +347,17 @@ public static IContainer OnRelease(Action action) return Handler.OnRelease(action); } + /// + /// 调用一个已经被绑定的方法 + /// + /// 方法名 + /// 用户提供的参数 + /// 调用结果 + public static object Invoke(string method, params object[] userParams) + { + return Handler.Invoke(method, userParams); + } + /// /// 以依赖注入形式调用一个方法 /// @@ -738,6 +750,68 @@ public static bool BindIf(string service, Func con return Handler.BindIf(service, concrete, out bindData); } + /// + /// 绑定一个方法到容器 + /// + /// 方法名 + /// 调用目标 + /// 调用方法 + /// 方法绑定数据 + public static IMethodBind BindMethod(string method, object target, MethodInfo call) + { + return Handler.BindMethod(method, target, call); + } + + /// + /// 绑定一个方法到容器 + /// + /// 方法名 + /// 调用方法 + public static IMethodBind BindMethod(string method, Func callback) + { + return Handler.BindMethod(method, callback); + } + + /// + /// 绑定一个方法到容器 + /// + /// 方法名 + /// 调用方法 + public static IMethodBind BindMethod(string method, Func callback) + { + return Handler.BindMethod(method, callback); + } + + /// + /// 绑定一个方法到容器 + /// + /// 方法名 + /// 调用方法 + public static IMethodBind BindMethod(string method, Func callback) + { + return Handler.BindMethod(method, callback); + } + + /// + /// 绑定一个方法到容器 + /// + /// 方法名 + /// 调用方法 + public static IMethodBind BindMethod(string method, Func callback) + { + return Handler.BindMethod(method, callback); + } + + /// + /// 绑定一个方法到容器 + /// + /// 方法名 + /// 调用方法 + public static IMethodBind BindMethod(string method, Func callback) + { + return Handler.BindMethod(method, callback); + } + /// /// 构造一个服务 /// @@ -767,5 +841,26 @@ public static void Instance(object instance) { Handler.Instance(instance); } + + /// + /// 在回调区间内暂时性的静态化服务实例 + /// + /// 回调区间 + /// 服务名 + /// 实例名 + public static void Flash(Action callback, string service, object instance) + { + Handler.Flash(callback, service, instance); + } + + /// + /// 在回调区间内暂时性的静态化服务实例 + /// + /// 回调区间 + /// 服务映射 + public static void Flash(Action callback, params KeyValuePair[] serviceMapping) + { + Handler.Flash(callback, serviceMapping); + } } } \ No newline at end of file diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 77f5dfd..f220813 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -747,21 +747,15 @@ public virtual string Type2Service(Type type) } /// - /// 在回调区间内暂时性的静态化一个服务实例 + /// 在回调区间内暂时性的静态化服务实例 /// /// 回调区间 - /// 服务映射 - public void Flash(Action callback, params KeyValuePair[] services) + /// 服务映射 + public void Flash(Action callback, params KeyValuePair[] serviceMapping) { - if (services.Length <= 0) - { - callback.Invoke(); - return; - } - lock (syncRoot) { - foreach (var service in services) + foreach (var service in serviceMapping) { if (HasInstance(service.Key)) { @@ -769,24 +763,10 @@ public void Flash(Action callback, params KeyValuePair[] service } } - var index = 0; - try - { - foreach (var service in services) - { - ++index; - Instance(service.Key, service.Value); - } - - callback.Invoke(); - } - finally - { - while (--index >= 0) - { - Release(services[index].Key); - } - } + Arr.Flash(serviceMapping, + service => Instance(service.Key, service.Value), + service => Release(service.Key), + callback); } } @@ -1261,9 +1241,10 @@ private void TriggerOnRebound(string service) { foreach (var callback in GetOnReboundCallbacks(service)) { - callback(instance); + callback.Invoke(instance); } - }, new KeyValuePair(Type2Service(typeof(IBindData)), bind)); + }, new KeyValuePair(Type2Service(typeof(IBindData)), bind), + new KeyValuePair(Type2Service(typeof(BindData)), bind)); } /// diff --git a/src/CatLib.Core/Support/Container/ContainerExtend.cs b/src/CatLib.Core/Support/Container/ContainerExtend.cs index 3571670..7857212 100644 --- a/src/CatLib.Core/Support/Container/ContainerExtend.cs +++ b/src/CatLib.Core/Support/Container/ContainerExtend.cs @@ -10,6 +10,7 @@ */ using System; +using System.Collections.Generic; namespace CatLib { @@ -365,6 +366,71 @@ public static bool BindIf(this IContainer container, string service, return container.BindIf(service, concrete, false, out bindData); } + /// + /// 绑定一个方法到容器 + /// + /// 服务容器 + /// 方法名 + /// 调用方法 + public static IMethodBind BindMethod(this IContainer container, string method, Func callback) + { + Guard.Requires(method != null); + Guard.Requires(callback != null); + return container.BindMethod(method, callback.Target, callback.Method); + } + + /// + /// 绑定一个方法到容器 + /// + /// 服务容器 + /// 方法名 + /// 调用方法 + public static IMethodBind BindMethod(this IContainer container, string method, Func callback) + { + Guard.Requires(method != null); + Guard.Requires(callback != null); + return container.BindMethod(method, callback.Target, callback.Method); + } + + /// + /// 绑定一个方法到容器 + /// + /// 服务容器 + /// 方法名 + /// 调用方法 + public static IMethodBind BindMethod(this IContainer container, string method, Func callback) + { + Guard.Requires(method != null); + Guard.Requires(callback != null); + return container.BindMethod(method, callback.Target, callback.Method); + } + + /// + /// 绑定一个方法到容器 + /// + /// 服务容器 + /// 方法名 + /// 调用方法 + public static IMethodBind BindMethod(this IContainer container, string method, Func callback) + { + Guard.Requires(method != null); + Guard.Requires(callback != null); + return container.BindMethod(method, callback.Target, callback.Method); + } + + /// + /// 绑定一个方法到容器 + /// + /// 服务容器 + /// 方法名 + /// 调用方法 + public static IMethodBind BindMethod(this IContainer container, string method, Func callback) + { + Guard.Requires(method != null); + Guard.Requires(callback != null); + return container.BindMethod(method, callback.Target, callback.Method); + } + /// /// 为服务设定一个别名 /// @@ -449,5 +515,17 @@ public static void Watch(this IContainer container, string service, object targe var methodInfo = target.GetType().GetMethod(method); container.Watch(service, target, methodInfo); } + + /// + /// 在回调区间内暂时性的静态化服务实例 + /// + /// 服务容器 + /// 回调区间 + /// 服务名 + /// 实例名 + public static void Flash(this IContainer container, Action callback, string service, object instance) + { + container.Flash(callback, new KeyValuePair(service, instance)); + } } } \ No newline at end of file diff --git a/src/CatLib.Core/Support/Container/IContainer.cs b/src/CatLib.Core/Support/Container/IContainer.cs index a0dbb0d..a96722e 100644 --- a/src/CatLib.Core/Support/Container/IContainer.cs +++ b/src/CatLib.Core/Support/Container/IContainer.cs @@ -10,6 +10,7 @@ */ using System; +using System.Collections.Generic; using System.Reflection; namespace CatLib @@ -92,6 +93,15 @@ public interface IContainer /// 是否成功绑定 bool BindIf(string service, Type concrete, bool isStatic, out IBindData bindData); + /// + /// 绑定一个方法到容器 + /// + /// 方法名 + /// 调用目标 + /// 调用方法 + /// 方法绑定数据 + IMethodBind BindMethod(string method, object target, MethodInfo call); + /// /// 为一个及以上的服务定义一个标记 /// @@ -124,6 +134,14 @@ public interface IContainer /// void Flush(); + /// + /// 调用一个已经被绑定的方法 + /// + /// 方法名 + /// 用户提供的参数 + /// 调用结果 + object Invoke(string method, params object[] userParams); + /// /// 以依赖注入形式调用一个方法 /// @@ -202,6 +220,13 @@ public interface IContainer /// 方法信息 void Watch(string service, object target, MethodInfo methodInfo); + /// + /// 在回调区间内暂时性的静态化服务实例 + /// + /// 回调区间 + /// 服务映射 + void Flash(Action callback, params KeyValuePair[] serviceMapping); + /// /// 类型转为服务名 /// diff --git a/src/CatLib.Core/Support/Util/Arr.cs b/src/CatLib.Core/Support/Util/Arr.cs index c75d828..2250835 100644 --- a/src/CatLib.Core/Support/Util/Arr.cs +++ b/src/CatLib.Core/Support/Util/Arr.cs @@ -526,5 +526,43 @@ public static T RemoveAt(ref T[] source, int index) var result = Splice(ref source, index, 1); return result.Length > 0 ? result[0] : default(T); } + + /// + /// 临时性的回调元素,如果遇到异常或者完成回调后会进行回滚元素回调 + /// + /// 数组类型 + /// 规定数组 + /// 顺序回调 + /// 所有回调完成后 + /// 回滚回调 + public static void Flash(T[] source, Action process, Action rollback, Action completed) + { + Guard.Requires(source != null); + + if (source.Length <= 0) + { + completed.Invoke(); + return; + } + + var index = 0; + try + { + foreach (var result in source) + { + ++index; + process.Invoke(result); + } + + completed(); + } + finally + { + while (--index >= 0) + { + rollback.Invoke(source[index]); + } + } + } } } \ No newline at end of file From b62fc01d0afd1a04ae252ce2d74397dd2afbfc95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Tue, 12 Dec 2017 15:04:58 +0800 Subject: [PATCH 47/91] container optimization --- .../Support/Container/Container.cs | 60 +++++++++++++++---- 1 file changed, 50 insertions(+), 10 deletions(-) diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index f220813..8a1441f 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -1365,16 +1365,7 @@ private object CreateInstance(Bindable makeServiceBindData, Type makeServiceType return null; } - var constructor = makeServiceType.GetConstructors(); - if (constructor.Length > 0) - { - var parameter = constructor[constructor.Length - 1].GetParameters(); - userParams = parameter.Length > 0 ? GetDependencies(makeServiceBindData, parameter, userParams) : null; - } - else - { - userParams = null; - } + userParams = GetConstructorsParams(makeServiceBindData, makeServiceType, userParams); try { @@ -1386,6 +1377,55 @@ private object CreateInstance(Bindable makeServiceBindData, Type makeServiceType } } + /// + /// 获取构造函数参数 + /// + /// 服务绑定数据 + /// 服务类型 + /// 用户传入的构造参数 + /// 构造函数参数 + private object[] GetConstructorsParams(Bindable makeServiceBindData, Type makeServiceType, object[] userParams) + { + var constructors = makeServiceType.GetConstructors(); + if (constructors.Length <= 0) + { + return null; + } + + Exception exception = null; + foreach (var constructor in constructors) + { + var parameter = constructor.GetParameters(); + if (parameter.Length <= 0) + { + return null; + } + + try + { + userParams = GetDependencies(makeServiceBindData, parameter, userParams); + if (userParams.Length == parameter.Length) + { + return userParams; + } + } + catch (Exception ex) + { + if (exception == null) + { + exception = ex; + } + } + } + + if (exception != null) + { + throw exception; + } + + return null; + } + /// /// 获取服务绑定数据,如果数据为null则填充数据 /// From 1a4ce628e17e54079cfd33bb7fc94e4d168c1219 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Tue, 12 Dec 2017 15:54:07 +0800 Subject: [PATCH 48/91] container optimization --- .../Support/Container/Container.cs | 100 +++++++++--------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 8a1441f..9587675 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -1199,6 +1199,55 @@ protected virtual string AliasToService(string service) return aliases.TryGetValue(service, out alias) ? alias : service; } + /// + /// 获取构造函数参数 + /// + /// 服务绑定数据 + /// 服务类型 + /// 用户传入的构造参数 + /// 构造函数参数 + protected virtual object[] GetConstructorsInjectParams(Bindable makeServiceBindData, Type makeServiceType, object[] userParams) + { + var constructors = makeServiceType.GetConstructors(); + if (constructors.Length <= 0) + { + return null; + } + + Exception exception = null; + foreach (var constructor in constructors) + { + var parameter = constructor.GetParameters(); + if (parameter.Length <= 0) + { + return null; + } + + try + { + userParams = GetDependencies(makeServiceBindData, parameter, userParams); + if (userParams.Length == parameter.Length) + { + return userParams; + } + } + catch (Exception ex) + { + if (exception == null) + { + exception = ex; + } + } + } + + if (exception != null) + { + throw exception; + } + + return null; + } + /// /// 触发全局解决修饰器 /// @@ -1365,7 +1414,7 @@ private object CreateInstance(Bindable makeServiceBindData, Type makeServiceType return null; } - userParams = GetConstructorsParams(makeServiceBindData, makeServiceType, userParams); + userParams = GetConstructorsInjectParams(makeServiceBindData, makeServiceType, userParams); try { @@ -1377,55 +1426,6 @@ private object CreateInstance(Bindable makeServiceBindData, Type makeServiceType } } - /// - /// 获取构造函数参数 - /// - /// 服务绑定数据 - /// 服务类型 - /// 用户传入的构造参数 - /// 构造函数参数 - private object[] GetConstructorsParams(Bindable makeServiceBindData, Type makeServiceType, object[] userParams) - { - var constructors = makeServiceType.GetConstructors(); - if (constructors.Length <= 0) - { - return null; - } - - Exception exception = null; - foreach (var constructor in constructors) - { - var parameter = constructor.GetParameters(); - if (parameter.Length <= 0) - { - return null; - } - - try - { - userParams = GetDependencies(makeServiceBindData, parameter, userParams); - if (userParams.Length == parameter.Length) - { - return userParams; - } - } - catch (Exception ex) - { - if (exception == null) - { - exception = ex; - } - } - } - - if (exception != null) - { - throw exception; - } - - return null; - } - /// /// 获取服务绑定数据,如果数据为null则填充数据 /// From ae384455d32cf492c5f938de091e2aeab8fd554d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Tue, 12 Dec 2017 17:37:49 +0800 Subject: [PATCH 49/91] container semantic optimization --- src/CatLib.Core/Support/Container/Container.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 9587675..542c5a4 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -224,7 +224,7 @@ public IBindData GetBind(string service) /// 服务是否被绑定 public bool HasBind(string service) { - return GetBind(service) != null || HasInstance(service); + return GetBind(service) != null; } /// @@ -268,7 +268,7 @@ public bool CanMake(string service) lock (syncRoot) { service = AliasToService(service); - return HasBind(service) || SpeculatedServiceType(service) != null; + return HasBind(service) || HasInstance(service) || SpeculatedServiceType(service) != null; } } @@ -824,6 +824,7 @@ protected virtual bool TryChangeType(object param, Type conversionType, out obje catch (Exception) { // ignored + // when throw exception then stop inject } result = null; @@ -976,7 +977,7 @@ protected virtual object SpeculationServiceByParamName(Bindable makeServiceBindD /// protected virtual string GetBuildStackDebugMessage() { - var previous = string.Join(", ", buildStack.ToArray()); + var previous = string.Join(", ", BuildStack.ToArray()); return " While building [" + previous + "]."; } From bc19e0e6c74f4545c4e1ce6fa05f58922de7bb9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Tue, 12 Dec 2017 18:10:33 +0800 Subject: [PATCH 50/91] container optimization & bug fixed --- src/CatLib.Core/Support/Container/Container.cs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 542c5a4..4fb1333 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -761,6 +761,11 @@ public void Flash(Action callback, params KeyValuePair[] service { throw new RuntimeException("Flash service [" + service.Key + "] is already exists."); } + + if (HasBind(service.Key)) + { + throw new RuntimeException("Flash service [" + service.Key + "] name has be used for bind or alias."); + } } Arr.Flash(serviceMapping, @@ -949,13 +954,13 @@ protected virtual object ResloveClass(Bindable makeServiceBindData, string servi { return Make(makeServiceBindData.GetContextual(service)); } - catch (UnresolvableException ex) + catch (UnresolvableException) { if (baseParam.IsOptional) { return baseParam.DefaultValue; } - throw ex; + throw; } } @@ -1410,7 +1415,9 @@ private object CreateInstance(Bindable makeServiceBindData, Type makeServiceType { if (makeServiceType == null || makeServiceType.IsAbstract - || makeServiceType.IsInterface) + || makeServiceType.IsInterface + || makeServiceType.IsArray + || makeServiceType.IsEnum) { return null; } From 87288740be0c575538d903c10281116b7c55f5a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Tue, 12 Dec 2017 18:27:32 +0800 Subject: [PATCH 51/91] container optimization --- src/CatLib.Core/Support/Container/Container.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 4fb1333..48c7b4d 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -1049,9 +1049,9 @@ protected virtual string FormatService(string service) /// 需要实现自的类型 /// 生成的实例 /// 是否符合类型 - protected virtual bool CheckInstanceIsInstanceOfType(Type type, object instance) + protected virtual bool IsInstanceOfType(Type type, object instance) { - return instance == null || type.IsInstanceOfType(instance); + return type.IsInstanceOfType(instance); } /// @@ -1062,7 +1062,7 @@ protected virtual void GuardUserParamsCount(int count) { if (count > 255) { - throw new RuntimeException("Too many parameters , must be less than 255"); + throw new RuntimeException("Too many parameters , must be less or equal than 255"); } } @@ -1140,7 +1140,7 @@ protected virtual void AttributeInject(Bindable makeServiceBindData, object make instance = ResolveAttrPrimitive(makeServiceBindData, needService, property); } - if (!CheckInstanceIsInstanceOfType(property.PropertyType, instance)) + if (!IsInstanceOfType(property.PropertyType, instance)) { throw new UnresolvableException("[" + makeServiceBindData.Service + "] Attr inject type must be [" + property.PropertyType + "] , But instance is [" + instance.GetType() + "] , Make service is [" + needService + "]."); } @@ -1182,7 +1182,7 @@ protected virtual object[] GetDependencies(Bindable makeServiceBindData, Paramet param = ResolvePrimitive(makeServiceBindData, needService, baseParam); } - if (!CheckInstanceIsInstanceOfType(baseParam.ParameterType, param)) + if (!IsInstanceOfType(param)) { throw new UnresolvableException("[" + makeServiceBindData.Service + "] Params inject type must be [" + baseParam.ParameterType + "] , But instance is [" + param.GetType() + "] Make service is [" + needService + "]."); } From ca4d2230f4ed616590cc82b3990749508e33e249 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Tue, 12 Dec 2017 18:28:27 +0800 Subject: [PATCH 52/91] bug fixed --- src/CatLib.Core/Support/Container/Container.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 48c7b4d..6d360bd 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -1182,7 +1182,7 @@ protected virtual object[] GetDependencies(Bindable makeServiceBindData, Paramet param = ResolvePrimitive(makeServiceBindData, needService, baseParam); } - if (!IsInstanceOfType(param)) + if (!IsInstanceOfType(baseParam.ParameterType, param)) { throw new UnresolvableException("[" + makeServiceBindData.Service + "] Params inject type must be [" + baseParam.ParameterType + "] , But instance is [" + param.GetType() + "] Make service is [" + needService + "]."); } From 0d9e8c8ba39e4722d56a3f7bcac7e087fc64b960 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Tue, 12 Dec 2017 18:56:13 +0800 Subject: [PATCH 53/91] bug fixed --- .../Support/Container/Container.cs | 64 ++++++++++--------- 1 file changed, 35 insertions(+), 29 deletions(-) diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 6d360bd..c70ac9d 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -159,15 +159,12 @@ public void Tag(string tag, params string[] service) lock (syncRoot) { List list; - if (tags.TryGetValue(tag, out list)) + if (!tags.TryGetValue(tag, out list)) { - list.AddRange(service); - } - else - { - list = new List(service); - tags.Add(tag, list); + tags[tag] = list = new List(); + } + list.AddRange(service); } } @@ -183,20 +180,19 @@ public object[] Tagged(string tag) Guard.NotEmptyOrNull(tag, "tag"); lock (syncRoot) { - List serviceList; - if (!tags.TryGetValue(tag, out serviceList)) + List services; + if (!tags.TryGetValue(tag, out services)) { throw new RuntimeException("Tag [" + tag + "] is not exist."); } - var result = new List(); - - foreach (var tagService in serviceList) + var result = new object[services.Count]; + for (var i = 0; i < services.Count; i++) { - result.Add(Make(tagService)); + result[i] = Make(services[i]); } - return result.ToArray(); + return result; } } @@ -320,6 +316,7 @@ public IContainer Alias(string alias, string service) { throw new RuntimeException("Alias [" + alias + "] is already exists."); } + if (!binds.ContainsKey(service) && !instances.ContainsKey(service)) { throw new RuntimeException("You must Bind() or Instance() serivce before you can call Alias()."); @@ -328,14 +325,12 @@ public IContainer Alias(string alias, string service) aliases.Add(alias, service); List serviceList; - if (aliasesReverse.TryGetValue(service, out serviceList)) + if (!aliasesReverse.TryGetValue(service, out serviceList)) { + aliasesReverse[service] = serviceList = new List(); serviceList.Add(alias); } - else - { - aliasesReverse.Add(service, new List { alias }); - } + serviceList.Add(alias); } return this; @@ -1049,9 +1044,9 @@ protected virtual string FormatService(string service) /// 需要实现自的类型 /// 生成的实例 /// 是否符合类型 - protected virtual bool IsInstanceOfType(Type type, object instance) + protected virtual bool CanInject(Type type, object instance) { - return type.IsInstanceOfType(instance); + return instance == null || type.IsInstanceOfType(instance); } /// @@ -1140,7 +1135,7 @@ protected virtual void AttributeInject(Bindable makeServiceBindData, object make instance = ResolveAttrPrimitive(makeServiceBindData, needService, property); } - if (!IsInstanceOfType(property.PropertyType, instance)) + if (!CanInject(property.PropertyType, instance)) { throw new UnresolvableException("[" + makeServiceBindData.Service + "] Attr inject type must be [" + property.PropertyType + "] , But instance is [" + instance.GetType() + "] , Make service is [" + needService + "]."); } @@ -1182,7 +1177,7 @@ protected virtual object[] GetDependencies(Bindable makeServiceBindData, Paramet param = ResolvePrimitive(makeServiceBindData, needService, baseParam); } - if (!IsInstanceOfType(baseParam.ParameterType, param)) + if (!CanInject(baseParam.ParameterType, param)) { throw new UnresolvableException("[" + makeServiceBindData.Service + "] Params inject type must be [" + baseParam.ParameterType + "] , But instance is [" + param.GetType() + "] Make service is [" + needService + "]."); } @@ -1293,13 +1288,24 @@ private void TriggerOnRebound(string service) var bind = GetBind(service); Flash(() => - { - foreach (var callback in GetOnReboundCallbacks(service)) { - callback.Invoke(instance); - } - }, new KeyValuePair(Type2Service(typeof(IBindData)), bind), - new KeyValuePair(Type2Service(typeof(BindData)), bind)); + foreach (var callback in GetOnReboundCallbacks(service)) + { + callback.Invoke(instance); + } + }, Pair(typeof(IBindData), bind), + Pair(typeof(BindData), bind)); + } + + /// + /// 类型配实例配偶 + /// + /// 类型 + /// 实例 + /// 键值对 + private KeyValuePair Pair(Type type, object instance) + { + return new KeyValuePair(Type2Service(type), instance); } /// From f1389749c43c27ef1a320e3e034041d43752d5a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Tue, 12 Dec 2017 19:01:04 +0800 Subject: [PATCH 54/91] container optimization --- src/CatLib.Core/Support/Container/Container.cs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index c70ac9d..780be41 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -1154,7 +1154,7 @@ protected virtual void AttributeInject(Bindable makeServiceBindData, object make /// 生成的实例类型和需求类型不一致 protected virtual object[] GetDependencies(Bindable makeServiceBindData, ParameterInfo[] baseParams, object[] userParams) { - var results = new List(); + var results = new List(baseParams.Length); foreach (var baseParam in baseParams) { @@ -1226,11 +1226,7 @@ protected virtual object[] GetConstructorsInjectParams(Bindable makeServiceBindD try { - userParams = GetDependencies(makeServiceBindData, parameter, userParams); - if (userParams.Length == parameter.Length) - { - return userParams; - } + return GetDependencies(makeServiceBindData, parameter, userParams); } catch (Exception ex) { From 7e49f02b52bb9d758a78f5834ee67a1f586554db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Wed, 13 Dec 2017 10:14:54 +0800 Subject: [PATCH 55/91] bug fixed --- src/CatLib.Core/Support/Container/Container.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 780be41..3752a1e 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -328,7 +328,6 @@ public IContainer Alias(string alias, string service) if (!aliasesReverse.TryGetValue(service, out serviceList)) { aliasesReverse[service] = serviceList = new List(); - serviceList.Add(alias); } serviceList.Add(alias); } From ebe27bf3cddc9fe24c146113df850e097f118614 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Wed, 13 Dec 2017 12:16:28 +0800 Subject: [PATCH 56/91] unit test update --- .../Support/Container/ContainerTests.cs | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs index 4faa8d9..f21c3b8 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs @@ -141,7 +141,7 @@ public void CanBindIf() var container = MakeContainer(); IBindData bind1, bind2; var result1 = container.BindIf("CanBindIf", (cont, param) => "Hello", true, out bind1); - var result2 = container.BindIf("CanBindIf", (cont, param) => "World", false,out bind2); + var result2 = container.BindIf("CanBindIf", (cont, param) => "World", false, out bind2); Assert.AreSame(bind1, bind2); Assert.AreEqual(true, result1); @@ -1051,7 +1051,7 @@ public class TestMakeBasePrimitiveConstructor { public TestMakeBasePrimitiveConstructor(int value) { - + } } @@ -1088,7 +1088,7 @@ public object[][] GetUserParams() protected override void GuardResolveInstance(object instance, string makeService) { - + } } @@ -1648,7 +1648,8 @@ public void TestNoConstructorAccessClassFunction() try { container.Make(); - }catch(RuntimeException ex) + } + catch (RuntimeException ex) { isThrow = ex.InnerException.GetType() == typeof(MissingMethodException); } @@ -1737,7 +1738,7 @@ public class TestWatchCLass public IContainer container; - public void OnChange(int instance,IContainer container) + public void OnChange(int instance, IContainer container) { value = instance; this.container = container; @@ -1759,6 +1760,22 @@ public void TestWatch() Assert.AreSame(container, cls.container); } + [TestMethod] + public void TestInstanceAndDecorator() + { + var container = new Container(); + var oldObject = new object(); + object newObject = null; + container.OnResolving((bindData, obj) => + { + return newObject = new object(); + }); + + container.Instance("Hello", oldObject); + + Assert.AreSame(newObject, container["Hello"]); + } + [TestMethod] public void TestOccupiedKeyInstance() { From d3bd2a389aa8f1edc5cd08914f04df41a63c6b7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Wed, 13 Dec 2017 13:05:37 +0800 Subject: [PATCH 57/91] container optimization --- src/CatLib.Core/Support/Container/Container.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 3752a1e..1569106 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -793,7 +793,7 @@ protected virtual object GetDependenciesFromUserParams(ParameterInfo baseParam, } object result; - if (TryChangeType(userParam, baseParam.ParameterType, out result)) + if (ChangeType(userParam, baseParam.ParameterType, out result)) { Arr.RemoveAt(ref userParams, n); return result; @@ -804,13 +804,13 @@ protected virtual object GetDependenciesFromUserParams(ParameterInfo baseParam, } /// - /// 安全的转换参数 + /// 转换参数类型 /// /// 参数 /// 转换到的类型 /// 转换后的结果 /// 是否转换成功 - protected virtual bool TryChangeType(object param, Type conversionType, out object result) + protected virtual bool ChangeType(object param, Type conversionType, out object result) { try { From 76fa0e613f3ef56316d5592160203fa3e400066d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Thu, 14 Dec 2017 15:19:20 +0800 Subject: [PATCH 58/91] method container update --- .../CatLib.Core.Tests.csproj | 1 + .../Support/Container/ContainerTests.cs | 39 +++++ .../Support/Container/MethodContainerTests.cs | 134 +++++++++++++++++- .../Support/Util/ArrTests.cs | 13 ++ .../Support/Util/StrTests.cs | 15 ++ src/CatLib.Core/CatLib/App.cs | 44 ++++++ src/CatLib.Core/Support/Container/BindData.cs | 7 +- .../Support/Container/Container.cs | 66 +++++---- .../Support/Container/ContainerExtend.cs | 25 ++++ .../Support/Container/IContainer.cs | 19 ++- .../Support/Container/MethodBind.cs | 11 +- .../Support/Container/MethodContainer.cs | 48 +++++-- src/CatLib.Core/Support/Util/Str.cs | 49 +++++++ 13 files changed, 420 insertions(+), 51 deletions(-) diff --git a/src/CatLib.Core.Tests/CatLib.Core.Tests.csproj b/src/CatLib.Core.Tests/CatLib.Core.Tests.csproj index 943d967..5c2881e 100644 --- a/src/CatLib.Core.Tests/CatLib.Core.Tests.csproj +++ b/src/CatLib.Core.Tests/CatLib.Core.Tests.csproj @@ -36,6 +36,7 @@ + diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs index f21c3b8..66a4bb3 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs @@ -85,6 +85,30 @@ public void CanMakeWithTaged() }); } + [TestMethod] + public void TestUnbind() + { + var container = MakeContainer(); + container.Bind("TestService1", (app, param) => "hello"); + container.Bind("TestService2", (app, param) => "world").Alias(); + + container.Unbind("TestService1"); + container.Unbind(); + + ExceptionAssert.Throws(() => + { + container.Make("TestService1"); + }); + + ExceptionAssert.Throws(() => + { + container.Make("TestService2"); + }); + + container.Bind("TestService2", (app, param) => "hello"); + Assert.AreEqual("hello", container["TestService2"]); + } + /// /// 测试不存在的Tag /// @@ -1797,6 +1821,21 @@ public void TestOccupiedKeyInstance() Assert.AreEqual(true, isThrow); } + + [TestMethod] + public void TestFlashOnBind() + { + var container = new Application(); + container.Bind((c, p) => 100); + + ExceptionAssert.Throws(() => + { + App.Flash(() => + { + + }, App.Type2Service(typeof(IBindData)), 200); + }); + } #endregion /// diff --git a/src/CatLib.Core.Tests/Support/Container/MethodContainerTests.cs b/src/CatLib.Core.Tests/Support/Container/MethodContainerTests.cs index 5304e36..42202ef 100644 --- a/src/CatLib.Core.Tests/Support/Container/MethodContainerTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/MethodContainerTests.cs @@ -9,20 +9,148 @@ * Document: http://catlib.io/ */ +using CatLib.Tests; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace CatLib.Core.Tests.Support.Container { [TestClass] - class MethodContainerTests + public class MethodContainerTests { [TestMethod] public void TestBindMethod() { - App.BindMethod("TestMethod", () => + new Application(); + App.BindMethod("TestMethod", () => 10); + App.BindMethod("TestMethodContainer", (IContainer container) => container != null); + App.BindMethod("TestMethodContainer2", (IContainer container, IContainer container2) => { - return null; + Assert.AreSame(container, container2); + return container != null; }); + App.BindMethod("TestMethodInputNum", (IApplication application, IContainer container, int num) => num); + App.BindMethod("TestMethodInputNum2", (IApplication application, IContainer container, int num, float num2) => num2); + + Assert.AreEqual(10, App.Invoke("TestMethod")); + Assert.AreEqual(true, App.Invoke("TestMethodContainer")); + Assert.AreEqual(true, App.Invoke("TestMethodContainer2")); + Assert.AreEqual(1000, App.Invoke("TestMethodInputNum", 1000, 2000)); + Assert.AreEqual((float) 2000, App.Invoke("TestMethodInputNum2", 1000, 2000, 3000)); + } + + [TestMethod] + public void UnBindMethodWithMethodName() + { + new Application(); + App.BindMethod("TestMethod10", () => 10); + App.BindMethod("TestMethod20", () => 20); + + App.UnbindMethod("TestMethod10"); + + ExceptionAssert.Throws(() => + { + App.Invoke("TestMethod10"); + }); + + Assert.AreEqual(20, App.Invoke("TestMethod20")); + } + + public class TestContainerClass + { + public int Func1(IContainer container, int input) + { + return input; + } + + public float Func2(IContainer container, int input, float input2) + { + return input2; + } + } + + [TestMethod] + public void TestBindExcistsMethod() + { + new Application(); + var cls = new TestContainerClass(); + App.BindMethod("Helloworld.Func1", cls); + ExceptionAssert.Throws(() => + { + App.BindMethod("Helloworld.Func1", cls); + }); + } + + [TestMethod] + public void TestUnbindWithObject() + { + new Application(); + var cls = new TestContainerClass(); + App.BindMethod("Helloworld.Func1", cls); + App.BindMethod("Helloworld.Func2", cls); + + var cls2 = new TestContainerClass(); + App.BindMethod("Helloworld2.Func1", cls2); + App.BindMethod("Helloworld2.Func2", cls2); + + App.UnbindMethod(cls); + App.UnbindMethod(cls); // double unbind test + App.UnbindMethod("UnknowMethod"); + + ExceptionAssert.Throws(() => + { + App.Invoke("Helloworld.Func1", 1000, 2000); + }); + + ExceptionAssert.Throws(() => + { + App.Invoke("Helloworld.Func2", 1000, 2000); + }); + + Assert.AreEqual(1000, App.Invoke("Helloworld2.Func1", 1000, 2000)); + Assert.AreEqual((float)2000, App.Invoke("Helloworld2.Func2", 1000, 2000)); + } + + [TestMethod] + public void TestContainerMethodContextual() + { + new Application(); + App.Instance("@input", 1000); + App.Instance("@input2", 2000); + + var cls = new TestContainerClass(); + App.BindMethod("Helloworld.Func1", cls).Needs("@input").Given("@input2"); + App.BindMethod("Helloworld.Func2", cls) + .Needs("@input").Given("@input2") + .Needs("@input2").Given("@input"); ; + + Assert.AreEqual(2000, App.Invoke("Helloworld.Func1")); + Assert.AreEqual((float)1000, App.Invoke("Helloworld.Func2")); + } + + [TestMethod] + public void TestFlush() + { + new Application(); + var cls = new TestContainerClass(); + var bind1 = App.BindMethod("Helloworld.Func1", cls); + var bind2 = App.BindMethod("Helloworld.Func2", cls); + + App.Handler.Flush(); + + ExceptionAssert.Throws(() => + { + App.Invoke("Helloworld.Func1", 1000, 2000); + }); + + ExceptionAssert.Throws(() => + { + App.Invoke("Helloworld.Func2", 1000, 2000); + }); + + App.UnbindMethod(cls); + App.UnbindMethod(cls); // double unbind test + App.UnbindMethod(bind1); + App.UnbindMethod(bind2); } } } diff --git a/src/CatLib.Core.Tests/Support/Util/ArrTests.cs b/src/CatLib.Core.Tests/Support/Util/ArrTests.cs index d855197..35eb714 100644 --- a/src/CatLib.Core.Tests/Support/Util/ArrTests.cs +++ b/src/CatLib.Core.Tests/Support/Util/ArrTests.cs @@ -620,5 +620,18 @@ public void TestRemoveAtNegativeNumber() Assert.AreEqual(null, result); Assert.AreEqual(0, data.Length); } + + [TestMethod] + public void TestEmptyFlash() + { + var data = new int[] { }; + var isCall = false; + Arr.Flash(data, (i) => { }, (o) => { }, () => + { + isCall = true; + }); + + Assert.AreEqual(true, isCall); + } } } diff --git a/src/CatLib.Core.Tests/Support/Util/StrTests.cs b/src/CatLib.Core.Tests/Support/Util/StrTests.cs index a948b75..1b75ae8 100644 --- a/src/CatLib.Core.Tests/Support/Util/StrTests.cs +++ b/src/CatLib.Core.Tests/Support/Util/StrTests.cs @@ -308,5 +308,20 @@ public void TestTruncate() str = Str.Truncate("喵h喵e越l来l越l漂o亮!了", 12); Assert.AreEqual("喵h喵e越l来l越...", str); } + + [TestMethod] + public void TestStrMethod() + { + Assert.AreEqual("GetNameSpace", Str.Method("Helloworld.GetNameSpace")); + Assert.AreEqual("GetNameSpace", Str.Method("Helloworld.GetNameSpace()")); + Assert.AreEqual("Space", Str.Method("Helloworld.GetName@Space()")); + Assert.AreEqual("_Space", Str.Method("Helloworld.GetName@_Space()")); + Assert.AreEqual("g8975GetNameSpace", Str.Method("Helloworld.g8975GetNameSpace()")); + Assert.AreEqual("GetNameSpace", Str.Method("Helloworld.8975GetNameSpace()")); + Assert.AreEqual("ame_Space", Str.Method("Helloworld.8975GetN(;)ame_Space()")); + Assert.AreEqual("GetName_Space", Str.Method("Helloworld.8GetName_Space()")); + Assert.AreEqual(string.Empty, Str.Method(null)); + Assert.AreEqual(string.Empty, Str.Method(string.Empty)); + } } } diff --git a/src/CatLib.Core/CatLib/App.cs b/src/CatLib.Core/CatLib/App.cs index 5c7b43e..9cf334d 100644 --- a/src/CatLib.Core/CatLib/App.cs +++ b/src/CatLib.Core/CatLib/App.cs @@ -570,6 +570,15 @@ public static string Type2Service(Type type) return Handler.Type2Service(type); } + /// + /// 解除服务绑定 + /// + /// 解除绑定的服务 + public static void Unbind() + { + Handler.Unbind(); + } + /// /// 以单例的形式绑定一个服务 /// @@ -750,6 +759,18 @@ public static bool BindIf(string service, Func con return Handler.BindIf(service, concrete, out bindData); } + /// + /// 绑定一个方法到容器 + /// + /// 方法名 + /// 调用目标 + /// 调用方法 + public static IMethodBind BindMethod(string method, object target, + string call = null) + { + return Handler.BindMethod(method, target, call); + } + /// /// 绑定一个方法到容器 /// @@ -812,6 +833,29 @@ public static IMethodBind BindMethod(string method, Func + /// 解除绑定的方法 + /// + /// + /// 解除目标 + /// 如果为字符串则作为调用方法名 + /// 如果为IMethodBind则作为指定方法 + /// 如果为其他对象则作为调用目标做全体解除 + /// + public static void UnbindMethod(object target) + { + Handler.UnbindMethod(target); + } + + /// + /// 解除绑定服务 + /// + /// 服务名或者别名 + public static void Unbind(string service) + { + Handler.Unbind(service); + } + /// /// 构造一个服务 /// diff --git a/src/CatLib.Core/Support/Container/BindData.cs b/src/CatLib.Core/Support/Container/BindData.cs index 7debed9..babe0e0 100644 --- a/src/CatLib.Core/Support/Container/BindData.cs +++ b/src/CatLib.Core/Support/Container/BindData.cs @@ -95,11 +95,6 @@ public IBindData OnResolving(Func func) resolving = new List>(); } resolving.Add(func); - - if (Container.HasInstance(Service)) - { - - } } return this; } @@ -133,7 +128,7 @@ public IBindData OnRelease(Action action) /// protected override void ReleaseBind() { - Container.Unbind(Service); + Container.Unbind(this); } /// diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 1569106..075d835 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -264,7 +264,14 @@ public bool CanMake(string service) lock (syncRoot) { service = AliasToService(service); - return HasBind(service) || HasInstance(service) || SpeculatedServiceType(service) != null; + + if (HasBind(service) || HasInstance(service)) + { + return true; + } + + var type = SpeculatedServiceType(service); + return !(type == null || type.IsPrimitive); } } @@ -712,21 +719,33 @@ public void Watch(string service, object target, MethodInfo methodInfo) /// 服务名或者别名 public void Unbind(string service) { - lock (syncRoot) + service = AliasToService(service); + var bind = GetBind(service); + if (bind != null) { - service = AliasToService(service); + bind.Unbind(); + } + } - Release(service); + /// + /// 解除绑定服务 + /// + /// 绑定关系 + internal void Unbind(IBindable bindable) + { + lock (syncRoot) + { + Release(bindable.Service); List serviceList; - if (aliasesReverse.TryGetValue(service, out serviceList)) + if (aliasesReverse.TryGetValue(bindable.Service, out serviceList)) { foreach (var alias in serviceList) { aliases.Remove(alias); } - aliasesReverse.Remove(service); + aliasesReverse.Remove(bindable.Service); } - binds.Remove(service); + binds.Remove(bindable.Service); } } @@ -856,13 +875,7 @@ protected virtual string GetParamNeedsService(ParameterInfo baseParam) return needService; } - var propertyAttrs = baseParam.GetCustomAttributes(injectTarget, false); - if (propertyAttrs.Length <= 0) - { - return needService; - } - - var injectAttr = (InjectAttribute)propertyAttrs[0]; + var injectAttr = (InjectAttribute)baseParam.GetCustomAttributes(injectTarget, false)[0]; if (!string.IsNullOrEmpty(injectAttr.Alias)) { needService = injectAttr.Alias; @@ -885,7 +898,7 @@ protected virtual object ResolveAttrPrimitive(Bindable makeServiceBindData, stri return Make(service); } - var result = SpeculationServiceByParamName(makeServiceBindData, baseParam.Name); + var result = SpeculationServiceByParamName(makeServiceBindData, baseParam.Name, baseParam.PropertyType); if (result != null) { return result; @@ -921,7 +934,7 @@ protected virtual object ResolvePrimitive(Bindable makeServiceBindData, string s return Make(service); } - var result = SpeculationServiceByParamName(makeServiceBindData, baseParam.Name); + var result = SpeculationServiceByParamName(makeServiceBindData, baseParam.Name, baseParam.ParameterType); if (result != null) { return result; @@ -963,11 +976,20 @@ protected virtual object ResloveClass(Bindable makeServiceBindData, string servi /// /// 请求注入操作的服务绑定数据 /// 参数名 + /// 参数类型 /// 推测的服务 - protected virtual object SpeculationServiceByParamName(Bindable makeServiceBindData, string paramName) + protected virtual object SpeculationServiceByParamName(Bindable makeServiceBindData, string paramName, Type paramType) { var service = makeServiceBindData.GetContextual("@" + paramName); - return CanMake(service) ? Make(service) : null; + + if (!CanMake(service)) + { + return null; + } + + var instance = Make(service); + ChangeType(instance, paramType, out instance); + return instance; } /// @@ -1236,12 +1258,8 @@ protected virtual object[] GetConstructorsInjectParams(Bindable makeServiceBindD } } - if (exception != null) - { - throw exception; - } - - return null; + Guard.Requires(exception != null); + throw exception; } /// diff --git a/src/CatLib.Core/Support/Container/ContainerExtend.cs b/src/CatLib.Core/Support/Container/ContainerExtend.cs index 7857212..09a75d0 100644 --- a/src/CatLib.Core/Support/Container/ContainerExtend.cs +++ b/src/CatLib.Core/Support/Container/ContainerExtend.cs @@ -166,6 +166,16 @@ public static IBindData Singleton(this IContainer container, string service, return container.Bind(service, concrete, true); } + /// + /// 解除服务绑定 + /// + /// 解除绑定的服务 + /// 服务容器 + public static void Unbind(this IContainer container) + { + container.Unbind(container.Type2Service(typeof(T))); + } + /// /// 以单例的形式绑定一个服务 /// @@ -366,6 +376,21 @@ public static bool BindIf(this IContainer container, string service, return container.BindIf(service, concrete, false, out bindData); } + /// + /// 绑定一个方法到容器 + /// + /// 服务容器 + /// 方法名 + /// 调用目标 + /// 调用方法 + public static IMethodBind BindMethod(this IContainer container, string method, object target, string call = null) + { + Guard.NotEmptyOrNull(method, "method"); + Guard.Requires(target != null); + + return container.BindMethod(method, target, target.GetType().GetMethod(call ?? Str.Method(method))); + } + /// /// 绑定一个方法到容器 /// diff --git a/src/CatLib.Core/Support/Container/IContainer.cs b/src/CatLib.Core/Support/Container/IContainer.cs index a96722e..3c77430 100644 --- a/src/CatLib.Core/Support/Container/IContainer.cs +++ b/src/CatLib.Core/Support/Container/IContainer.cs @@ -102,6 +102,23 @@ public interface IContainer /// 方法绑定数据 IMethodBind BindMethod(string method, object target, MethodInfo call); + /// + /// 解除绑定的方法 + /// + /// + /// 解除目标 + /// 如果为字符串则作为调用方法名 + /// 如果为IMethodBind则作为指定方法 + /// 如果为其他对象则作为调用目标做全体解除 + /// + void UnbindMethod(object target); + + /// + /// 解除绑定服务 + /// + /// 服务名或者别名 + void Unbind(string service); + /// /// 为一个及以上的服务定义一个标记 /// @@ -130,7 +147,7 @@ public interface IContainer void Release(string service); /// - /// 清空容器的所有实例,绑定,别名,标签,解决器 + /// 清空容器的所有实例,绑定,别名,标签,解决器,方法容器 /// void Flush(); diff --git a/src/CatLib.Core/Support/Container/MethodBind.cs b/src/CatLib.Core/Support/Container/MethodBind.cs index 69b7b64..b909d02 100644 --- a/src/CatLib.Core/Support/Container/MethodBind.cs +++ b/src/CatLib.Core/Support/Container/MethodBind.cs @@ -33,16 +33,23 @@ internal sealed class MethodBind : Bindable , IMethodBind /// public ParameterInfo[] ParameterInfos { get; private set; } + /// + /// 方法容器 + /// + private readonly MethodContainer methodContainer; + /// /// 构建一个绑定数据 /// + /// 方法容器 /// 依赖注入容器 /// 服务名 /// 调用目标 /// 调用信息 - public MethodBind(Container container, string service, object target, MethodInfo call) + public MethodBind(MethodContainer methodContainer, Container container, string service, object target, MethodInfo call) :base(container, service) { + this.methodContainer = methodContainer; Target = target; MethodInfo = call; ParameterInfos = call.GetParameters(); @@ -53,7 +60,7 @@ public MethodBind(Container container, string service, object target, MethodInfo /// protected override void ReleaseBind() { - Container.UnbindMethod(this); + methodContainer.Unbind(this); } } } diff --git a/src/CatLib.Core/Support/Container/MethodContainer.cs b/src/CatLib.Core/Support/Container/MethodContainer.cs index 9ccb263..e9d8d4a 100644 --- a/src/CatLib.Core/Support/Container/MethodContainer.cs +++ b/src/CatLib.Core/Support/Container/MethodContainer.cs @@ -85,12 +85,12 @@ public IMethodBind Bind(string method, object target, MethodInfo call) targetToMethodsMappings[target] = targetMappings = new List(); } - var methodBind = new MethodBind(container, method, target, call); + var methodBind = new MethodBind(this, container, method, target, call); methodMappings[method] = methodBind; targetMappings.Add(method); - return null; + return methodBind; } } @@ -136,10 +136,20 @@ public void Unbind(object target) lock (syncRoot) { var methodBind = target as MethodBind; - if (methodBind != null || - (target is string && methodMappings.TryGetValue(target.ToString(), out methodBind))) + + if (methodBind != null) + { + methodBind.Unbind(); + return; + } + + if (target is string) { - UnbindWithMethodBind(methodBind); + if (!methodMappings.TryGetValue(target.ToString(), out methodBind)) + { + return; + } + methodBind.Unbind(); return; } @@ -148,17 +158,26 @@ public void Unbind(object target) } /// - /// 根据方法绑定信息解除绑定 + /// 解除绑定 /// - /// 方法绑定信息 - private void UnbindWithMethodBind(MethodBind methodBind) + /// 方法绑定 + internal void Unbind(MethodBind methodBind) { - methodMappings.Remove(methodBind.Service); - - List methods; - if (targetToMethodsMappings.TryGetValue(methodBind.Target, out methods)) + lock (syncRoot) { + methodMappings.Remove(methodBind.Service); + List methods; + if (!targetToMethodsMappings.TryGetValue(methodBind.Target, out methods)) + { + return; + } + methods.Remove(methodBind.Service); + + if (methods.Count <= 0) + { + targetToMethodsMappings.Remove(methodBind.Target); + } } } @@ -174,10 +193,9 @@ private void UnbindWithObject(object target) return; } - targetToMethodsMappings.Remove(target); - foreach (var method in methods) + foreach (var method in methods.ToArray()) { - methodMappings.Remove(method); + Unbind(method); } } diff --git a/src/CatLib.Core/Support/Util/Str.cs b/src/CatLib.Core/Support/Util/Str.cs index 3416630..a5103d3 100644 --- a/src/CatLib.Core/Support/Util/Str.cs +++ b/src/CatLib.Core/Support/Util/Str.cs @@ -10,6 +10,7 @@ */ using System; +using System.Collections.Specialized; using System.Text; using System.Text.RegularExpressions; @@ -41,6 +42,54 @@ public enum PadTypes Right } + /// + /// 获取字符串所表达的函数名 + /// + /// 输入字符串 + /// 函数名 + public static string Method(string pattern) + { + if (string.IsNullOrEmpty(pattern)) + { + return string.Empty; + } + + var chars = new char[pattern.Length]; + var count = 0; + for (var i = pattern.Length - 1; i >= 0; i--) + { + var segment = pattern[i]; + if ((segment >= 'A' && segment <= 'Z') + || (segment >= 'a' && segment <= 'z') + || (segment >= '0' && segment <= '9') + || segment == '_') + { + chars[count++] = segment; + continue; + } + + if (count > 0) + { + break; + } + } + + for (var i = count - 1; i >= 0; i--) + { + if ((chars[i] >= '0' && chars[i] <= '9')) + { + count--; + continue; + } + break; + } + + Array.Resize(ref chars, count); + Array.Reverse(chars); + + return new string(chars); + } + /// /// 将规定字符串翻译为星号匹配表达式 /// 即删减正则表达式中除了星号外的所有功能 From 883eb9b7b6d1dc60e1d4a45e3cd1b300d72c6500 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Thu, 14 Dec 2017 15:25:10 +0800 Subject: [PATCH 59/91] readme update --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 19b9a92..460c268 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ **使用Nuget安装** ```PM -Install-Package CatLib.Core -Version 1.1.4 +Install-Package CatLib.Core -Version 1.2.0 ``` **直接下载发布版本** From d8db4caecf047f990fd0dbac483c3e834b678477 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Thu, 14 Dec 2017 18:58:33 +0800 Subject: [PATCH 60/91] dispatcher rebuild --- .../Support/Container/MethodBind.cs | 2 +- src/CatLib.Core/Support/Events/Event.cs | 75 +++++ src/CatLib.Core/Support/Events/IEvent.cs | 24 ++ .../Support/Events/NewDispatcher.cs | 258 ++++++++++++++++++ 4 files changed, 358 insertions(+), 1 deletion(-) create mode 100644 src/CatLib.Core/Support/Events/Event.cs create mode 100644 src/CatLib.Core/Support/Events/IEvent.cs create mode 100644 src/CatLib.Core/Support/Events/NewDispatcher.cs diff --git a/src/CatLib.Core/Support/Container/MethodBind.cs b/src/CatLib.Core/Support/Container/MethodBind.cs index b909d02..3ecceec 100644 --- a/src/CatLib.Core/Support/Container/MethodBind.cs +++ b/src/CatLib.Core/Support/Container/MethodBind.cs @@ -45,7 +45,7 @@ internal sealed class MethodBind : Bindable , IMethodBind /// 依赖注入容器 /// 服务名 /// 调用目标 - /// 调用信息 + /// 调用方法 public MethodBind(MethodContainer methodContainer, Container container, string service, object target, MethodInfo call) :base(container, service) { diff --git a/src/CatLib.Core/Support/Events/Event.cs b/src/CatLib.Core/Support/Events/Event.cs new file mode 100644 index 0000000..e3c9ae8 --- /dev/null +++ b/src/CatLib.Core/Support/Events/Event.cs @@ -0,0 +1,75 @@ +/* + * 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 +{ + /// + /// 事件对象 + /// + internal class Event : IEvent + { + /// + /// 调用事件 + /// + public Action Call { get; private set; } + + /// + /// 事件名 + /// + public string EventName { get; private set; } + + /// + /// 事件目标 + /// + public object Target { get; private set; } + + /// + /// 调度器 + /// + private readonly NewDispatcher dispatcher; + + /// + /// 是否被释放 + /// + private bool isOff; + + /// + /// 创建一个事件对象 + /// + /// 调度器 + /// 事件名 + /// 调用方法目标 + /// 调用方法 + public Event(NewDispatcher dispatcher, string eventName, object target, Action call) + { + this.dispatcher = dispatcher; + EventName = eventName; + Target = target; + Call = call; + isOff = false; + } + + /// + /// 释放事件 + /// + public void Off() + { + if (isOff) + { + return; + } + isOff = true; + dispatcher.Off(this); + } + } +} diff --git a/src/CatLib.Core/Support/Events/IEvent.cs b/src/CatLib.Core/Support/Events/IEvent.cs new file mode 100644 index 0000000..9b73d60 --- /dev/null +++ b/src/CatLib.Core/Support/Events/IEvent.cs @@ -0,0 +1,24 @@ +/* + * 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/ + */ + +namespace CatLib +{ + /// + /// 事件 + /// + public interface IEvent + { + /// + /// 撤销事件 + /// + void Off(); + } +} diff --git a/src/CatLib.Core/Support/Events/NewDispatcher.cs b/src/CatLib.Core/Support/Events/NewDispatcher.cs new file mode 100644 index 0000000..3f629d2 --- /dev/null +++ b/src/CatLib.Core/Support/Events/NewDispatcher.cs @@ -0,0 +1,258 @@ +/* + * 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; +using System.Collections.Generic; +using System.Reflection; +using System.Text.RegularExpressions; + +namespace CatLib +{ + /// + /// 事件调度器 + /// + public class NewDispatcher + { + /// + /// 调用方法目标 映射到 事件句柄 + /// + private readonly Dictionary> targetMapping; + + /// + /// 普通事件列表 + /// + private readonly Dictionary> listeners; + + /// + /// 通配符事件列表 + /// + private readonly Dictionary>> wildcardListeners; + + /// + /// 依赖注入容器 + /// + private readonly IContainer container; + + /// + /// 同步锁 + /// + private readonly object syncRoot; + + /// + /// 构建一个事件调度器 + /// + /// 依赖注入容器 + public NewDispatcher(IContainer container) + { + Guard.Requires(container != null); + + this.container = container; + syncRoot = new object(); + targetMapping = new Dictionary>(); + listeners = new Dictionary>(); + wildcardListeners = new Dictionary>>(); + } + + /// + /// 触发一个事件 + /// + /// 事件名 + /// 载荷 + /// + public object[] Trigger(string eventName, params object[] payloads) + { + return null; + } + + /// + /// 注册一个事件 + /// + /// 事件名 + /// 事件调用目标 + /// 事件调用方法 + /// 事件对象 + public IEvent On(string eventName, object target, MethodInfo method) + { + Guard.NotEmptyOrNull(eventName, "eventName"); + Guard.Requires(target != null); + Guard.Requires(method != null); + + lock (syncRoot) + { + eventName = FormatEventName(eventName); + + var result = eventName.IndexOf('*') != -1 + ? SetupWildcardListen(eventName, target, method) + : SetupListen(eventName, target, method); + + List listener; + if (!targetMapping.TryGetValue(target, out listener)) + { + targetMapping[target] = listener = new List(); + } + listener.Add(result); + + return result; + } + } + + /// + /// 解除事件注册 + /// + /// + /// 事件解除目标 + /// 如果传入的是字符串(string)将会解除对应事件名的事件 + /// 如果传入的是事件对象(IEvent)那么解除对应事件 + /// 如果传入的是其他实例(object)会解除该实例下的所有事件 + /// + public void Off(object target) + { + + } + + /// + /// 解除事件 + /// + /// 目标事件 + internal void Off(Event target) + { + lock (syncRoot) + { + List events; + if (targetMapping.TryGetValue(target.Target, out events)) + { + events.Remove(target); + if (events.Count <= 0) + { + targetMapping.Remove(target.Target); + } + } + + if (target.EventName.IndexOf('*') != -1) + { + DestoryWildcardListen(target); + } + else + { + DestoryListen(target); + } + } + } + + /// + /// 销毁普通事件 + /// + /// 事件对象 + private void DestoryListen(Event target) + { + List events; + if (!listeners.TryGetValue(target.EventName, out events)) + { + return; + } + + events.Remove(target); + if (events.Count <= 0) + { + listeners.Remove(target.EventName); + } + } + + /// + /// 销毁通配符事件 + /// + /// 事件对象 + private void DestoryWildcardListen(Event target) + { + KeyValuePair> wildcardEvents; + if (!wildcardListeners.TryGetValue(target.EventName, out wildcardEvents)) + { + return; + } + + wildcardEvents.Value.Remove(target); + if (wildcardEvents.Value.Count <= 0) + { + wildcardListeners.Remove(target.EventName); + } + } + + /// + /// 设定普通事件 + /// + /// 事件名 + /// 事件调用目标 + /// 事件调用方法 + /// 监听事件 + private Event SetupListen(string eventName, object target, MethodInfo method) + { + List listener; + if (!listeners.TryGetValue(eventName, out listener)) + { + listeners[eventName] = listener = new List(); + } + + Event output; + listener.Add(output = new Event(this, eventName, target, MakeListener(target, method))); + return output; + } + + /// + /// 设定通配符事件 + /// + /// 事件名 + /// 事件调用目标 + /// 事件调用方法 + /// 监听事件 + private Event SetupWildcardListen(string eventName, object target, MethodInfo method) + { + eventName = Str.AsteriskWildcard(eventName); + + KeyValuePair> listener; + if (!wildcardListeners.TryGetValue(eventName, out listener)) + { + wildcardListeners[eventName] = listener = + new KeyValuePair>(new Regex(eventName), new List()); + } + + Event output; + listener.Value.Add(output = new Event(this, eventName, target, MakeListener(target, method, true))); + return output; + } + + /// + /// 创建事件监听器 + /// + /// 调用目标 + /// 调用方法 + /// 是否是通配符方法 + /// 事件监听器 + protected virtual Action MakeListener(object target, MethodInfo method, bool isWildcard = false) + { + return (eventName, payloads) => + { + container.Call(target, method, isWildcard + ? Arr.Merge(new object[] { method }, payloads) + : payloads); + }; + } + + /// + /// 格式化事件名 + /// + /// 事件名 + /// 格式化后的事件名 + protected virtual string FormatEventName(string eventName) + { + return eventName; + } + } +} From e291088be114a328ad589a237b785157af6644cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Fri, 15 Dec 2017 16:43:14 +0800 Subject: [PATCH 61/91] event rebuild --- src/CatLib.Core/CatLib/App.cs | 147 +++++- src/CatLib.Core/CatLib/Application.cs | 79 ++-- .../Support/Container/Container.cs | 106 +++-- src/CatLib.Core/Support/Events/Dispatcher.cs | 445 ++++++++++++------ .../Support/Events/DispatcherExtend.cs | 155 ++++++ src/CatLib.Core/Support/Events/Event.cs | 37 +- .../Support/Events/EventHandler.cs | 121 ----- src/CatLib.Core/Support/Events/EventMethod.cs | 59 --- src/CatLib.Core/Support/Events/IDispatcher.cs | 46 +- src/CatLib.Core/Support/Events/IEvent.cs | 25 +- .../Support/Events/IEventHandler.cs | 34 -- .../Support/Events/NewDispatcher.cs | 258 ---------- 12 files changed, 775 insertions(+), 737 deletions(-) create mode 100644 src/CatLib.Core/Support/Events/DispatcherExtend.cs delete mode 100644 src/CatLib.Core/Support/Events/EventHandler.cs delete mode 100644 src/CatLib.Core/Support/Events/EventMethod.cs delete mode 100644 src/CatLib.Core/Support/Events/IEventHandler.cs delete mode 100644 src/CatLib.Core/Support/Events/NewDispatcher.cs diff --git a/src/CatLib.Core/CatLib/App.cs b/src/CatLib.Core/CatLib/App.cs index 9cf334d..0253343 100644 --- a/src/CatLib.Core/CatLib/App.cs +++ b/src/CatLib.Core/CatLib/App.cs @@ -157,48 +157,159 @@ public static DebugLevels DebugLevel /// 触发一个事件,并获取事件的返回结果 /// /// 事件名称 - /// 载荷 + /// 载荷 /// 事件结果 - public static object[] Trigger(string eventName, object payload = null) + public static object[] Trigger(string eventName, params object[] payloads) { - return Handler.Trigger(eventName, payload); + return Handler.Trigger(eventName, payloads); } /// /// 触发一个事件,遇到第一个事件存在处理结果后终止,并获取事件的返回结果 /// /// 事件名 - /// 载荷 + /// 载荷 /// 事件结果 - public static object TriggerHalt(string eventName, object payload = null) + public static object TriggerHalt(string eventName, params object[] payloads) { - return Handler.TriggerHalt(eventName, payload); + return Handler.TriggerHalt(eventName, payloads); + } + + + + /// + /// 注册一个事件监听器 + /// + /// 事件名称 + /// 事件调用目标 + /// 事件处理方法 + /// 事件对象 + public static IEvent On(string eventName, object target, string method = null) + { + return Handler.On(eventName, target, method); + } + + /// + /// 注册一个事件监听器 + /// + /// 事件调度器 + /// 事件名称 + /// 事件处理方法 + /// 事件对象 + public static IEvent On(this IDispatcher dispatcher, string eventName, Action method) + { + Guard.Requires(method != null); + return dispatcher.On(eventName, method.Target, method.Method); + } + + /// + /// 注册一个事件监听器 + /// + /// 事件调度器 + /// 事件名称 + /// 事件处理方法 + /// 事件对象 + public static IEvent On(this IDispatcher dispatcher, string eventName, Action method) + { + Guard.Requires(method != null); + return dispatcher.On(eventName, method.Target, method.Method); + } + + /// + /// 注册一个事件监听器 + /// + /// 事件调度器 + /// 事件名称 + /// 事件处理方法 + /// 事件对象 + public static IEvent On(this IDispatcher dispatcher, string eventName, Action method) + { + Guard.Requires(method != null); + return dispatcher.On(eventName, method.Target, method.Method); + } + + /// + /// 注册一个事件监听器 + /// + /// 事件调度器 + /// 事件名称 + /// 事件处理方法 + /// 事件对象 + public static IEvent On(this IDispatcher dispatcher, string eventName, Action method) + { + Guard.Requires(method != null); + return dispatcher.On(eventName, method.Target, method.Method); + } + + /// + /// 注册一个事件监听器 + /// + /// 事件调度器 + /// 事件名称 + /// 事件处理方法 + /// 事件对象 + public static IEvent Listen(this IDispatcher dispatcher, string eventName, Func method) + { + Guard.Requires(method != null); + return dispatcher.On(eventName, method.Target, method.Method); } /// - /// 注册一个事件 + /// 注册一个事件监听器 /// + /// 事件调度器 /// 事件名称 - /// 事件句柄 - /// 在几次后事件会被自动释放 - /// 事件句柄 - public static IEventHandler On(string eventName, Action handler, int life = 0) + /// 事件处理方法 + /// 事件对象 + public static IEvent Listen(this IDispatcher dispatcher, string eventName, Func method) { - return Handler.On(eventName, handler, life); + Guard.Requires(method != null); + return dispatcher.On(eventName, method.Target, method.Method); } /// - /// 注册一个事件 + /// 注册一个事件监听器 /// + /// 事件调度器 /// 事件名称 - /// 事件句柄 - /// 在几次后事件会被自动释放 - /// 事件句柄 - public static IEventHandler Listen(string eventName, Func handler, int life = 0) + /// 事件处理方法 + /// 事件对象 + public static IEvent Listen(this IDispatcher dispatcher, string eventName, Func method) { - return Handler.Listen(eventName, handler, life); + Guard.Requires(method != null); + return dispatcher.On(eventName, method.Target, method.Method); } + /// + /// 注册一个事件监听器 + /// + /// 事件调度器 + /// 事件名称 + /// 事件处理方法 + /// 事件对象 + public static IEvent Listen(this IDispatcher dispatcher, string eventName, Func method) + { + Guard.Requires(method != null); + return dispatcher.On(eventName, method.Target, method.Method); + } + + /// + /// 注册一个事件监听器 + /// + /// 事件调度器 + /// 事件名称 + /// 事件处理方法 + /// 事件对象 + public static IEvent Listen(this IDispatcher dispatcher, string eventName, Func method) + { + Guard.Requires(method != null); + return dispatcher.On(eventName, method.Target, method.Method); + } + + + + + /// /// 获取服务的绑定数据,如果绑定不存在则返回null /// diff --git a/src/CatLib.Core/CatLib/Application.cs b/src/CatLib.Core/CatLib/Application.cs index 9a2ef16..84e6b74 100644 --- a/src/CatLib.Core/CatLib/Application.cs +++ b/src/CatLib.Core/CatLib/Application.cs @@ -11,6 +11,7 @@ using System; using System.Collections.Generic; +using System.Reflection; using System.Threading; namespace CatLib @@ -23,7 +24,7 @@ public class Application : Container, IApplication /// /// 版本号 /// - private readonly Version version = new Version("1.1.0"); + private readonly Version version = new Version("1.2.0"); /// /// 框架启动流程 @@ -284,46 +285,58 @@ public DebugLevels DebugLevel /// 触发一个事件,并获取事件的返回结果 /// /// 事件名称 - /// 载荷 + /// 载荷 /// 事件结果 - public object[] Trigger(string eventName, object payload = null) + public object[] Trigger(string eventName, params object[] payloads) { - return Dispatcher.Trigger(eventName, payload); + return Dispatcher.Trigger(eventName, payloads); } /// /// 触发一个事件,遇到第一个事件存在处理结果后终止,并获取事件的返回结果 /// /// 事件名 - /// 载荷 + /// 载荷 /// 事件结果 - public object TriggerHalt(string eventName, object payload = null) + public object TriggerHalt(string eventName, params object[] payloads) { - return Dispatcher.TriggerHalt(eventName, payload); + return Dispatcher.TriggerHalt(eventName, payloads); } /// - /// 注册一个事件 + /// 判断给定事件是否存在事件监听器 /// - /// 事件名称 - /// 事件句柄 - /// 在几次后事件会被自动释放 - /// 事件句柄 - public IEventHandler On(string eventName, Action handler, int life = 0) + /// 事件名 + /// 是否存在事件监听器 + public bool HasListeners(string eventName) { - return Dispatcher.On(eventName, handler, life); + return Dispatcher.HasListeners(eventName); } /// - /// 注册一个事件 + /// 注册一个事件监听器 /// /// 事件名称 - /// 事件句柄 - /// 在几次后事件会被自动释放 - /// 事件句柄 - public IEventHandler Listen(string eventName, Func handler, int life = 0) + /// 调用目标 + /// 调用方法 + /// 事件对象 + public IEvent On(string eventName, object target, MethodInfo method) + { + return Dispatcher.On(eventName, target, method); + } + + /// + /// 解除注册的事件监听器 + /// + /// + /// 事件解除目标 + /// 如果传入的是字符串(string)将会解除对应事件名的所有事件 + /// 如果传入的是事件对象(IEvent)那么解除对应事件 + /// 如果传入的是其他实例(object)会解除该实例下的所有事件 + /// + public void Off(object target) { - return Dispatcher.Listen(eventName, handler, life); + Dispatcher.Off(target); } /// @@ -368,21 +381,10 @@ public int Compare(string version) return this.version.Compare(version); } - /// - /// 获取服务提供者基础类型 - /// - /// 服务提供者 - /// 基础类型 - private Type GetProviderBaseType(IServiceProvider provider) - { - var providerType = provider as IServiceProviderType; - return providerType == null ? provider.GetType() : providerType.BaseType; - } - /// /// 注册核心别名 /// - private void RegisterCoreAlias() + protected virtual void RegisterCoreAlias() { var application = Type2Service(typeof(Application)); Instance(application, this); @@ -400,9 +402,20 @@ private void RegisterCoreAlias() /// /// 注册核心服务 /// - private void RegisterCoreService() + protected virtual void RegisterCoreService() { this.Singleton().Alias(); } + + /// + /// 获取服务提供者基础类型 + /// + /// 服务提供者 + /// 基础类型 + private Type GetProviderBaseType(IServiceProvider provider) + { + var providerType = provider as IServiceProviderType; + return providerType == null ? provider.GetType() : providerType.BaseType; + } } } \ No newline at end of file diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 075d835..fdce776 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -596,35 +596,6 @@ public void Release(string service) } } - /// - /// 清空容器的所有实例,绑定,别名,标签,解决器 - /// - public void Flush() - { - lock (syncRoot) - { - foreach (var service in Dict.Keys(instances)) - { - Release(service); - } - - tags.Clear(); - aliases.Clear(); - aliasesReverse.Clear(); - instances.Clear(); - binds.Clear(); - resolving.Clear(); - release.Clear(); - resolved.Clear(); - findType.Clear(); - findTypeCache.Clear(); - buildStack.Clear(); - userParamsStack.Clear(); - rebound.Clear(); - methodContainer.Flush(); - } - } - /// /// 当查找类型无法找到时会尝试去调用开发者提供的查找类型函数 /// @@ -727,6 +698,45 @@ public void Unbind(string service) } } + /// + /// 清空容器的所有实例,绑定,别名,标签,解决器 + /// + public virtual void Flush() + { + lock (syncRoot) + { + foreach (var service in Dict.Keys(instances)) + { + Release(service); + } + + tags.Clear(); + aliases.Clear(); + aliasesReverse.Clear(); + instances.Clear(); + binds.Clear(); + resolving.Clear(); + release.Clear(); + resolved.Clear(); + findType.Clear(); + findTypeCache.Clear(); + buildStack.Clear(); + userParamsStack.Clear(); + rebound.Clear(); + methodContainer.Flush(); + } + } + + /// + /// 将类型转为服务名 + /// + /// 类型 + /// 服务名 + public virtual string Type2Service(Type type) + { + return type.ToString(); + } + /// /// 解除绑定服务 /// @@ -749,16 +759,6 @@ internal void Unbind(IBindable bindable) } } - /// - /// 将类型转为服务名 - /// - /// 类型 - /// 服务名 - public virtual string Type2Service(Type type) - { - return type.ToString(); - } - /// /// 在回调区间内暂时性的静态化服务实例 /// @@ -1165,6 +1165,23 @@ protected virtual void AttributeInject(Bindable makeServiceBindData, object make } } + /// + /// 检查是否可以紧缩注入用户传入的参数 + /// + /// 服务实例的参数信息 + /// 输入的构造参数列表 + /// 是否可以紧缩注入 + protected virtual bool CheckCompactInjectUserParams(ParameterInfo baseParams, object[] userParams) + { + if (userParams.Length <= 0) + { + return false; + } + + return baseParams.GetType() == typeof(object[]) + || baseParams.GetType() == typeof(object); + } + /// /// 获取依赖解决结果 /// @@ -1179,6 +1196,16 @@ protected virtual object[] GetDependencies(Bindable makeServiceBindData, Paramet foreach (var baseParam in baseParams) { + // 当容器发现开发者使用 object 或者 object[] 作为参数类型时 + // 我们尝试将所有用户传入的用户参数紧缩注入 + if (CheckCompactInjectUserParams(baseParam, userParams)) + { + results.Add(userParams); + userParams = null; + continue; + } + + // 从用户传入的参数中挑选合适的参数,按照相对顺序依次注入 var param = GetDependenciesFromUserParams(baseParam, ref userParams); if (param != null) { @@ -1186,6 +1213,7 @@ protected virtual object[] GetDependencies(Bindable makeServiceBindData, Paramet continue; } + // 尝试通过依赖注入容器来生成所需求的参数 var needService = GetParamNeedsService(baseParam); if (baseParam.ParameterType.IsClass diff --git a/src/CatLib.Core/Support/Events/Dispatcher.cs b/src/CatLib.Core/Support/Events/Dispatcher.cs index ce1e56d..a858d6e 100644 --- a/src/CatLib.Core/Support/Events/Dispatcher.cs +++ b/src/CatLib.Core/Support/Events/Dispatcher.cs @@ -11,6 +11,7 @@ using System; using System.Collections.Generic; +using System.Reflection; using System.Text.RegularExpressions; namespace CatLib @@ -18,263 +19,445 @@ namespace CatLib /// /// 事件调度器 /// - public sealed class Dispatcher : IDispatcher + public class Dispatcher : IDispatcher { /// - /// 事件句柄 + /// 调用方法目标 映射到 事件句柄 /// - private readonly Dictionary> handlers; + private readonly Dictionary> targetMapping; /// - /// 通配符事件句柄 + /// 普通事件列表 /// - private readonly Dictionary> wildcardHandlers; + private readonly Dictionary> listeners; /// - /// 同步锁 + /// 通配符事件列表 /// - private readonly object syncRoot; + private readonly Dictionary>> wildcardListeners; /// - /// 跳出标记 + /// 依赖注入容器 /// - private readonly object breakFlag = false; + private readonly IContainer container; /// /// 依赖注入容器 /// - private IContainer container; + protected IContainer Container + { + get { return container; } + } + + /// + /// 同步锁 + /// + private readonly object syncRoot; + + /// + /// 跳出标记 + /// + protected virtual object BreakFlag + { + get { return false; } + } /// - /// 调度器 + /// 构建一个事件调度器 /// + /// 依赖注入容器 public Dispatcher(IContainer container) { + Guard.Requires(container != null); + this.container = container; - handlers = new Dictionary>(); - wildcardHandlers = new Dictionary>(); syncRoot = new object(); + targetMapping = new Dictionary>(); + listeners = new Dictionary>(); + wildcardListeners = new Dictionary>>(); + } + + /// + /// 判断给定事件是否存在事件监听器 + /// + /// 事件名 + /// 是否存在事件监听器 + public bool HasListeners(string eventName) + { + eventName = FormatEventName(eventName); + lock (syncRoot) + { + return IsWildcard(eventName) + ? wildcardListeners.ContainsKey(eventName) + : listeners.ContainsKey(eventName); + } } /// - /// 触发一个事件,并获取事件的返回结果 + /// 触发一个事件,并获取事件监听器的返回结果 /// /// 事件名称 - /// 载荷 + /// 载荷 /// 事件结果 - public object[] Trigger(string eventName, object payload = null) + public object[] Trigger(string eventName, params object[] payloads) { - return Dispatch(eventName, payload) as object[]; + return Dispatch(false, eventName, payloads) as object[]; } /// - /// 触发一个事件,遇到第一个事件存在处理结果后终止,并获取事件的返回结果 + /// 触发一个事件,并获取事件监听器的返回结果 /// - /// 事件名 - /// 载荷 + /// 事件名称 + /// 载荷 /// 事件结果 - public object TriggerHalt(string eventName, object payload = null) + public object TriggerHalt(string eventName, params object[] payloads) + { + return Dispatch(true, eventName, payloads); + } + + /// + /// 注册一个事件监听器 + /// + /// 事件名称 + /// 调用目标 + /// 调用方法 + /// 事件对象 + public IEvent On(string eventName, object target, MethodInfo method) + { + Guard.NotEmptyOrNull(eventName, "eventName"); + Guard.Requires(target != null); + Guard.Requires(method != null); + + lock (syncRoot) + { + eventName = FormatEventName(eventName); + + var result = IsWildcard(eventName) + ? SetupWildcardListen(eventName, target, method) + : SetupListen(eventName, target, method); + + List listener; + if (!targetMapping.TryGetValue(target, out listener)) + { + targetMapping[target] = listener = new List(); + } + listener.Add(result); + + return result; + } + } + + /// + /// 解除注册的事件监听器 + /// + /// + /// 事件解除目标 + /// 如果传入的是字符串(string)将会解除对应事件名的所有事件 + /// 如果传入的是事件对象(IEvent)那么解除对应事件 + /// 如果传入的是其他实例(object)会解除该实例下的所有事件 + /// + public void Off(object target) + { + Guard.Requires(target != null); + + lock (syncRoot) + { + var baseEvent = target as IEvent; + if (baseEvent != null) + { + Forget(baseEvent); + return; + } + + if (target is string) + { + var eventName = FormatEventName(target.ToString()); + if (IsWildcard(eventName)) + { + DismissWildcardEventName(eventName); + } + else + { + DismissEventName(eventName); + } + return; + } + + DismissTargetObject(target); + } + } + + /// + /// 生成事件 + /// + /// 事件名 + /// 目标对象 + /// 调用方法 + /// 是否是通配符事件 + protected virtual IEvent MakeEvent(string eventName, object target, MethodInfo method, bool isWildcard = false) + { + return new Event(eventName, target, method, MakeListener(target, method, isWildcard)); + } + + /// + /// 创建事件监听器 + /// + /// 调用目标 + /// 调用方法 + /// 是否是通配符方法 + /// 事件监听器 + protected virtual Func MakeListener(object target, MethodInfo method, bool isWildcard = false) + { + return (eventName, payloads) => container.Call(target, method, isWildcard + ? Arr.Merge(new object[] { method }, payloads) + : payloads); + } + + /// + /// 格式化事件名 + /// + /// 事件名 + /// 格式化后的事件名 + protected virtual string FormatEventName(string eventName) { - return Dispatch(eventName, payload, true); + return eventName; } /// /// 调度事件 /// + /// 遇到第一个事件存在处理结果后终止 /// 事件名 /// 载荷 - /// 遇到第一个事件存在处理结果后终止 /// 处理结果 - private object Dispatch(string eventName, object payload = null, bool halt = false) + private object Dispatch(bool halt, string eventName, params object[] payload) { Guard.Requires(eventName != null); - eventName = Normalize(eventName); + eventName = FormatEventName(eventName); lock (syncRoot) { - var listeners = GetListeners(eventName); var outputs = new List(listeners.Count); - var triggerListener = new List(listeners.Count); - foreach (var listener in listeners) + foreach (var listener in GetListeners(eventName)) { - var result = listener.Trigger(payload); - triggerListener.Add(listener); + var response = listener.Call(payload); - if (halt && result != null) + // 如果启用了事件暂停,且得到的有效的响应那么我们终止事件调用 + if (halt && response != null) { - outputs.Add(result); - break; + return response; } - if (result != null && result.Equals(breakFlag)) + // 如果响应内容和终止标记相同那么我们终止事件调用 + if (response != null && response.Equals(BreakFlag)) { break; } - outputs.Add(result); + outputs.Add(response); } - foreach (var listener in triggerListener) + return halt ? null : outputs.ToArray(); + } + } + + /// + /// 获取指定事件的事件列表 + /// + /// 事件名 + /// 事件列表 + private IEnumerable GetListeners(string eventName) + { + var outputs = new List(); + + List result; + if (listeners.TryGetValue(eventName, out result)) + { + outputs.AddRange(result); + } + + foreach (var element in wildcardListeners) + { + if (element.Value.Key.IsMatch(eventName)) { - if (!listener.IsLife) - { - listener.Off(); - } + outputs.AddRange(element.Value.Value); } - - return halt ? outputs.Count <= 0 ? null : outputs[Math.Max(0, outputs.Count - 1)] : outputs.ToArray(); } + + return outputs; } /// - /// 注册一个事件 + /// 根据普通事件解除相关事件 /// - /// 事件名称 - /// 事件句柄 - /// 在几次后事件会被自动释放 - /// 事件句柄 - public IEventHandler On(string eventName, Action handler, int life = 0) + /// 事件名 + private void DismissEventName(string eventName) { - Guard.Requires(handler != null); - return Listen(eventName, (payload) => + List events; + if (!listeners.TryGetValue(eventName, out events)) { - handler.Invoke(payload); - return null; - }, life); + return; + } + + foreach (var element in events.ToArray()) + { + Forget(element); + } } /// - /// 注册一个事件 + /// 根据通配符事件解除相关事件 /// - /// 事件名称 - /// 事件句柄 - /// 在几次后事件会被自动释放 - /// 事件句柄 - public IEventHandler Listen(string eventName, Func handler, int life = 0) + /// 事件名 + private void DismissWildcardEventName(string eventName) { - Guard.Requires(eventName != null); - Guard.Requires(handler != null); - - eventName = Normalize(eventName); + KeyValuePair> events; + if (!wildcardListeners.TryGetValue(eventName, out events)) + { + return; + } - var wildcard = eventName.IndexOf("*") != -1; - var eventHandler = new EventHandler(this, wildcard ? Str.AsteriskWildcard(eventName) : eventName, handler, life); + foreach (var element in events.Value.ToArray()) + { + Forget(element); + } + } - lock (syncRoot) + /// + /// 根据Object解除事件 + /// + /// 事件解除目标 + private void DismissTargetObject(object target) + { + List events; + if (!targetMapping.TryGetValue(target, out events)) { - if (wildcard) - { - SetWildcardListener(eventHandler); - } - else - { - List handlers; - if (!this.handlers.TryGetValue(eventName, out handlers)) - { - this.handlers[eventName] = handlers = new List(); - } - handlers.Add(eventHandler); - } + return; + } - return eventHandler; + foreach (var element in events.ToArray()) + { + Forget(element); } } /// - /// 移除一个事件 + /// 从事件调度器中移除指定的事件监听器 /// - /// 事件句柄 - internal void Off(EventHandler handler) + /// 事件监听器 + private void Forget(IEvent target) { lock (syncRoot) { - List result; - if (handlers.TryGetValue(handler.EventName, out result)) + List events; + if (targetMapping.TryGetValue(target.Target, out events)) { - result.Remove(handler); - if (result.Count <= 0) + events.Remove(target); + if (events.Count <= 0) { - handlers.Remove(handler.EventName); + targetMapping.Remove(target.Target); } } - Regex wildcardkey = null; - foreach (var element in wildcardHandlers) + if (IsWildcard(target.EventName)) { - if (element.Key.ToString() == handler.EventName) - { - element.Value.Remove(handler); - wildcardkey = element.Key; - result = element.Value; - break; - } + ForgetWildcardListen(target); } - if (wildcardkey != null && result.Count <= 0) + else { - wildcardHandlers.Remove(wildcardkey); + ForgetListen(target); } } } /// - /// 设定通配符监听 + /// 销毁普通事件 /// - /// 监听句柄 - private void SetWildcardListener(EventHandler handler) + /// 事件对象 + private void ForgetListen(IEvent target) { - List handlers = null; - foreach (var element in wildcardHandlers) + List events; + if (!listeners.TryGetValue(target.EventName, out events)) { - if (element.Key.ToString() == handler.EventName) - { - handlers = element.Value; - break; - } + return; } - if (handlers == null) + events.Remove(target); + if (events.Count <= 0) { - wildcardHandlers[new Regex(handler.EventName)] = handlers = new List(); + listeners.Remove(target.EventName); } + } - handlers.Add(handler); + /// + /// 销毁通配符事件 + /// + /// 事件对象 + private void ForgetWildcardListen(IEvent target) + { + KeyValuePair> wildcardEvents; + if (!wildcardListeners.TryGetValue(target.EventName, out wildcardEvents)) + { + return; + } + + wildcardEvents.Value.Remove(target); + if (wildcardEvents.Value.Count <= 0) + { + wildcardListeners.Remove(target.EventName); + } } /// - /// 获取指定事件的事件句柄列表 + /// 设定普通事件 /// /// 事件名 - /// 句柄列表 - private IList GetListeners(string eventName) + /// 事件调用目标 + /// 事件调用方法 + /// 监听事件 + private IEvent SetupListen(string eventName, object target, MethodInfo method) { - var outputs = new List(); - - List result; - if (handlers.TryGetValue(eventName, out result)) + List listener; + if (!listeners.TryGetValue(eventName, out listener)) { - outputs.AddRange(result); + listeners[eventName] = listener = new List(); } - foreach (var element in wildcardHandlers) + var output = MakeEvent(eventName, target, method); + listener.Add(output); + return output; + } + + /// + /// 设定通配符事件 + /// + /// 事件名 + /// 事件调用目标 + /// 事件调用方法 + /// 监听事件 + private IEvent SetupWildcardListen(string eventName, object target, MethodInfo method) + { + KeyValuePair> listener; + if (!wildcardListeners.TryGetValue(eventName, out listener)) { - if (element.Key.IsMatch(eventName)) - { - outputs.AddRange(element.Value); - } + wildcardListeners[eventName] = listener = + new KeyValuePair>(new Regex(Str.AsteriskWildcard(eventName)), new List()); } - return outputs; + var output = MakeEvent(eventName, target, method, true); + listener.Value.Add(output); + return output; } /// - /// 标准化字符串 + /// 是否是通配符事件 /// - /// 输入 - /// 输出 - private string Normalize(string input) + /// 事件名 + /// 是否是通配符事件 + private bool IsWildcard(string eventName) { - return input.ToLower(); + return eventName.IndexOf('*') != -1; } } } diff --git a/src/CatLib.Core/Support/Events/DispatcherExtend.cs b/src/CatLib.Core/Support/Events/DispatcherExtend.cs new file mode 100644 index 0000000..82a783d --- /dev/null +++ b/src/CatLib.Core/Support/Events/DispatcherExtend.cs @@ -0,0 +1,155 @@ +/* + * 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 +{ + /// + /// 事件调度器扩展方法 + /// + public static class DispatcherExtend + { + /// + /// 注册一个事件监听器 + /// + /// 事件调度器 + /// 事件名称 + /// 事件调用目标 + /// 事件处理方法 + /// 事件对象 + public static IEvent On(this IDispatcher dispatcher, string eventName, object target, string method = null) + { + Guard.NotEmptyOrNull(eventName, "eventName"); + Guard.Requires(method != string.Empty); + Guard.Requires(target != null); + + return dispatcher.On(eventName, target, target.GetType().GetMethod(method ?? Str.Method(eventName))); + } + + /// + /// 注册一个事件监听器 + /// + /// 事件调度器 + /// 事件名称 + /// 事件处理方法 + /// 事件对象 + public static IEvent On(this IDispatcher dispatcher, string eventName, Action method) + { + Guard.Requires(method != null); + return dispatcher.On(eventName, method.Target, method.Method); + } + + /// + /// 注册一个事件监听器 + /// + /// 事件调度器 + /// 事件名称 + /// 事件处理方法 + /// 事件对象 + public static IEvent On(this IDispatcher dispatcher, string eventName, Action method) + { + Guard.Requires(method != null); + return dispatcher.On(eventName, method.Target, method.Method); + } + + /// + /// 注册一个事件监听器 + /// + /// 事件调度器 + /// 事件名称 + /// 事件处理方法 + /// 事件对象 + public static IEvent On(this IDispatcher dispatcher, string eventName, Action method) + { + Guard.Requires(method != null); + return dispatcher.On(eventName, method.Target, method.Method); + } + + /// + /// 注册一个事件监听器 + /// + /// 事件调度器 + /// 事件名称 + /// 事件处理方法 + /// 事件对象 + public static IEvent On(this IDispatcher dispatcher, string eventName, Action method) + { + Guard.Requires(method != null); + return dispatcher.On(eventName, method.Target, method.Method); + } + + /// + /// 注册一个事件监听器 + /// + /// 事件调度器 + /// 事件名称 + /// 事件处理方法 + /// 事件对象 + public static IEvent Listen(this IDispatcher dispatcher, string eventName, Func method) + { + Guard.Requires(method != null); + return dispatcher.On(eventName, method.Target, method.Method); + } + + /// + /// 注册一个事件监听器 + /// + /// 事件调度器 + /// 事件名称 + /// 事件处理方法 + /// 事件对象 + public static IEvent Listen(this IDispatcher dispatcher, string eventName, Func method) + { + Guard.Requires(method != null); + return dispatcher.On(eventName, method.Target, method.Method); + } + + /// + /// 注册一个事件监听器 + /// + /// 事件调度器 + /// 事件名称 + /// 事件处理方法 + /// 事件对象 + public static IEvent Listen(this IDispatcher dispatcher, string eventName, Func method) + { + Guard.Requires(method != null); + return dispatcher.On(eventName, method.Target, method.Method); + } + + /// + /// 注册一个事件监听器 + /// + /// 事件调度器 + /// 事件名称 + /// 事件处理方法 + /// 事件对象 + public static IEvent Listen(this IDispatcher dispatcher, string eventName, Func method) + { + Guard.Requires(method != null); + return dispatcher.On(eventName, method.Target, method.Method); + } + + /// + /// 注册一个事件监听器 + /// + /// 事件调度器 + /// 事件名称 + /// 事件处理方法 + /// 事件对象 + public static IEvent Listen(this IDispatcher dispatcher, string eventName, Func method) + { + Guard.Requires(method != null); + return dispatcher.On(eventName, method.Target, method.Method); + } + } +} diff --git a/src/CatLib.Core/Support/Events/Event.cs b/src/CatLib.Core/Support/Events/Event.cs index e3c9ae8..750b729 100644 --- a/src/CatLib.Core/Support/Events/Event.cs +++ b/src/CatLib.Core/Support/Events/Event.cs @@ -10,6 +10,7 @@ */ using System; +using System.Reflection; namespace CatLib { @@ -18,11 +19,6 @@ namespace CatLib /// internal class Event : IEvent { - /// - /// 调用事件 - /// - public Action Call { get; private set; } - /// /// 事件名 /// @@ -34,42 +30,37 @@ internal class Event : IEvent public object Target { get; private set; } /// - /// 调度器 + /// 方法信息 /// - private readonly NewDispatcher dispatcher; + public MethodInfo Method { get; private set; } /// - /// 是否被释放 + /// 事件调用 /// - private bool isOff; + private readonly Func transfer; /// /// 创建一个事件对象 /// - /// 调度器 /// 事件名 /// 调用方法目标 - /// 调用方法 - public Event(NewDispatcher dispatcher, string eventName, object target, Action call) + /// 目标方法 + /// 调用方法 + public Event(string eventName, object target, MethodInfo method, Func transfer) { - this.dispatcher = dispatcher; EventName = eventName; Target = target; - Call = call; - isOff = false; + Method = method; + this.transfer = transfer; } /// - /// 释放事件 + /// 调用事件 /// - public void Off() + /// 载荷 + public object Call(params object[] payloads) { - if (isOff) - { - return; - } - isOff = true; - dispatcher.Off(this); + return transfer(EventName, payloads); } } } diff --git a/src/CatLib.Core/Support/Events/EventHandler.cs b/src/CatLib.Core/Support/Events/EventHandler.cs deleted file mode 100644 index 44f9378..0000000 --- a/src/CatLib.Core/Support/Events/EventHandler.cs +++ /dev/null @@ -1,121 +0,0 @@ -/* - * 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 -{ - /// - /// 事件句柄 - /// - internal sealed class EventHandler : IEventHandler - { - /// - /// 剩余的调用次数 - /// - public int Life { get; private set; } - - /// - /// 事件是否是有效的 - /// - public bool IsLife { get; private set; } - - /// - /// 事件名 - /// - internal string EventName { get; private set; } - - /// - /// 调度器 - /// - private readonly Dispatcher dispatcher; - - /// - /// 事件句柄 - /// - private readonly Func handler; - - /// - /// 是否取消事件 - /// - private bool isCancel; - - /// - /// 调用计数 - /// - private int count; - - /// - /// 创建一个事件句柄 - /// - /// 调度器 - /// 事件名 - /// 事件句柄 - /// 生命次数 - internal EventHandler(Dispatcher dispatcher, string eventName, Func handler, int life) - { - this.dispatcher = dispatcher; - this.handler = handler; - - EventName = eventName; - Life = Math.Max(0, life); - IsLife = true; - - isCancel = false; - count = 0; - } - - /// - /// 撤销事件监听 - /// - /// 是否撤销成功 - public void Off() - { - if (count > 0 || isCancel) - { - return; - } - - dispatcher.Off(this); - isCancel = true; - } - - /// - /// 激活事件 - /// - /// 载荷 - internal object Trigger(object payload) - { - if (!IsLife) - { - return null; - } - - if (Life > 0) - { - if (--Life <= 0) - { - IsLife = false; - } - } - - count++; - - var result = handler.Invoke(payload); - - count--; - - Guard.Requires(count >= 0); - - return result; - } - } -} \ No newline at end of file diff --git a/src/CatLib.Core/Support/Events/EventMethod.cs b/src/CatLib.Core/Support/Events/EventMethod.cs deleted file mode 100644 index 3150016..0000000 --- a/src/CatLib.Core/Support/Events/EventMethod.cs +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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.Reflection; - -namespace CatLib -{ - /// - /// 事件方法 - /// - internal sealed class EventMethod - { - /// - /// 依赖注入容器 - /// - private readonly IContainer container; - - /// - /// 方法 - /// - private readonly MethodInfo method; - - /// - /// 实例目标 - /// - private readonly object target; - - /// - /// 创建一个事件句柄 - /// - /// 依赖注入容器 - /// 调用源 - /// 调用方法名 - public EventMethod(IContainer container, object target, string method) - { - this.container = container; - this.target = target; - this.method = target.GetType().GetMethod(method, - BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy); - } - - /// - /// 调用方法 - /// - /// 方法参数 - public object Call(params object[] args) - { - return container.Call(target, method, args); - } - } -} diff --git a/src/CatLib.Core/Support/Events/IDispatcher.cs b/src/CatLib.Core/Support/Events/IDispatcher.cs index 749b8cd..d50f4ff 100644 --- a/src/CatLib.Core/Support/Events/IDispatcher.cs +++ b/src/CatLib.Core/Support/Events/IDispatcher.cs @@ -10,46 +10,56 @@ */ using System; +using System.Reflection; namespace CatLib { /// - /// 调度器 + /// 事件调度器 /// public interface IDispatcher { /// - /// 触发一个事件,并获取事件的返回结果 + /// 判断给定事件是否存在事件监听器 + /// + /// 事件名 + /// 是否存在事件监听器 + bool HasListeners(string eventName); + + /// + /// 触发一个事件,并获取事件监听器的返回结果 /// /// 事件名称 - /// 载荷 + /// 载荷 /// 事件结果 - object[] Trigger(string eventName, object payload = null); + object[] Trigger(string eventName, params object[] payloads); /// - /// 触发一个事件,遇到第一个事件存在处理结果后终止,并获取事件的返回结果 + /// 触发一个事件,遇到第一个事件存在处理结果后终止,并获取事件监听器的返回结果 /// /// 事件名 - /// 载荷 + /// 载荷 /// 事件结果 - object TriggerHalt(string eventName, object payload = null); + object TriggerHalt(string eventName, params object[] payloads); /// - /// 注册一个事件 + /// 注册一个事件监听器 /// /// 事件名称 - /// 事件句柄 - /// 在几次后事件会被自动释放 - /// 事件句柄 - IEventHandler On(string eventName, Action handler, int life = 0); + /// 调用目标 + /// 调用方法 + /// 事件对象 + IEvent On(string eventName, object target, MethodInfo method); /// - /// 注册一个事件 + /// 解除注册的事件监听器 /// - /// 事件名称 - /// 事件句柄 - /// 在几次后事件会被自动释放 - /// 事件句柄 - IEventHandler Listen(string eventName, Func handler, int life = 0); + /// + /// 事件解除目标 + /// 如果传入的是字符串(string)将会解除对应事件名的所有事件 + /// 如果传入的是事件对象(IEvent)那么解除对应事件 + /// 如果传入的是其他实例(object)会解除该实例下的所有事件 + /// + void Off(object target); } } diff --git a/src/CatLib.Core/Support/Events/IEvent.cs b/src/CatLib.Core/Support/Events/IEvent.cs index 9b73d60..5d273b1 100644 --- a/src/CatLib.Core/Support/Events/IEvent.cs +++ b/src/CatLib.Core/Support/Events/IEvent.cs @@ -9,16 +9,35 @@ * Document: http://catlib.io/ */ +using System.Reflection; + namespace CatLib { /// - /// 事件 + /// 事件对象 /// public interface IEvent { /// - /// 撤销事件 + /// 事件名 + /// + string EventName { get; } + + /// + /// 事件目标 + /// + object Target { get; } + + /// + /// 方法信息 + /// + MethodInfo Method { get; } + + /// + /// 调用事件 /// - void Off(); + /// 载荷 + /// 事件结果 + object Call(params object[] payloads); } } diff --git a/src/CatLib.Core/Support/Events/IEventHandler.cs b/src/CatLib.Core/Support/Events/IEventHandler.cs deleted file mode 100644 index b305777..0000000 --- a/src/CatLib.Core/Support/Events/IEventHandler.cs +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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/ - */ - -namespace CatLib -{ - /// - /// 事件句柄 - /// - public interface IEventHandler - { - /// - /// 取消注册的事件 - /// - void Off(); - - /// - /// 剩余的调用次数,当为0时事件会被释放 - /// - int Life { get; } - - /// - /// 事件是否是有效的 - /// - bool IsLife { get; } - } -} \ No newline at end of file diff --git a/src/CatLib.Core/Support/Events/NewDispatcher.cs b/src/CatLib.Core/Support/Events/NewDispatcher.cs deleted file mode 100644 index 3f629d2..0000000 --- a/src/CatLib.Core/Support/Events/NewDispatcher.cs +++ /dev/null @@ -1,258 +0,0 @@ -/* - * 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; -using System.Collections.Generic; -using System.Reflection; -using System.Text.RegularExpressions; - -namespace CatLib -{ - /// - /// 事件调度器 - /// - public class NewDispatcher - { - /// - /// 调用方法目标 映射到 事件句柄 - /// - private readonly Dictionary> targetMapping; - - /// - /// 普通事件列表 - /// - private readonly Dictionary> listeners; - - /// - /// 通配符事件列表 - /// - private readonly Dictionary>> wildcardListeners; - - /// - /// 依赖注入容器 - /// - private readonly IContainer container; - - /// - /// 同步锁 - /// - private readonly object syncRoot; - - /// - /// 构建一个事件调度器 - /// - /// 依赖注入容器 - public NewDispatcher(IContainer container) - { - Guard.Requires(container != null); - - this.container = container; - syncRoot = new object(); - targetMapping = new Dictionary>(); - listeners = new Dictionary>(); - wildcardListeners = new Dictionary>>(); - } - - /// - /// 触发一个事件 - /// - /// 事件名 - /// 载荷 - /// - public object[] Trigger(string eventName, params object[] payloads) - { - return null; - } - - /// - /// 注册一个事件 - /// - /// 事件名 - /// 事件调用目标 - /// 事件调用方法 - /// 事件对象 - public IEvent On(string eventName, object target, MethodInfo method) - { - Guard.NotEmptyOrNull(eventName, "eventName"); - Guard.Requires(target != null); - Guard.Requires(method != null); - - lock (syncRoot) - { - eventName = FormatEventName(eventName); - - var result = eventName.IndexOf('*') != -1 - ? SetupWildcardListen(eventName, target, method) - : SetupListen(eventName, target, method); - - List listener; - if (!targetMapping.TryGetValue(target, out listener)) - { - targetMapping[target] = listener = new List(); - } - listener.Add(result); - - return result; - } - } - - /// - /// 解除事件注册 - /// - /// - /// 事件解除目标 - /// 如果传入的是字符串(string)将会解除对应事件名的事件 - /// 如果传入的是事件对象(IEvent)那么解除对应事件 - /// 如果传入的是其他实例(object)会解除该实例下的所有事件 - /// - public void Off(object target) - { - - } - - /// - /// 解除事件 - /// - /// 目标事件 - internal void Off(Event target) - { - lock (syncRoot) - { - List events; - if (targetMapping.TryGetValue(target.Target, out events)) - { - events.Remove(target); - if (events.Count <= 0) - { - targetMapping.Remove(target.Target); - } - } - - if (target.EventName.IndexOf('*') != -1) - { - DestoryWildcardListen(target); - } - else - { - DestoryListen(target); - } - } - } - - /// - /// 销毁普通事件 - /// - /// 事件对象 - private void DestoryListen(Event target) - { - List events; - if (!listeners.TryGetValue(target.EventName, out events)) - { - return; - } - - events.Remove(target); - if (events.Count <= 0) - { - listeners.Remove(target.EventName); - } - } - - /// - /// 销毁通配符事件 - /// - /// 事件对象 - private void DestoryWildcardListen(Event target) - { - KeyValuePair> wildcardEvents; - if (!wildcardListeners.TryGetValue(target.EventName, out wildcardEvents)) - { - return; - } - - wildcardEvents.Value.Remove(target); - if (wildcardEvents.Value.Count <= 0) - { - wildcardListeners.Remove(target.EventName); - } - } - - /// - /// 设定普通事件 - /// - /// 事件名 - /// 事件调用目标 - /// 事件调用方法 - /// 监听事件 - private Event SetupListen(string eventName, object target, MethodInfo method) - { - List listener; - if (!listeners.TryGetValue(eventName, out listener)) - { - listeners[eventName] = listener = new List(); - } - - Event output; - listener.Add(output = new Event(this, eventName, target, MakeListener(target, method))); - return output; - } - - /// - /// 设定通配符事件 - /// - /// 事件名 - /// 事件调用目标 - /// 事件调用方法 - /// 监听事件 - private Event SetupWildcardListen(string eventName, object target, MethodInfo method) - { - eventName = Str.AsteriskWildcard(eventName); - - KeyValuePair> listener; - if (!wildcardListeners.TryGetValue(eventName, out listener)) - { - wildcardListeners[eventName] = listener = - new KeyValuePair>(new Regex(eventName), new List()); - } - - Event output; - listener.Value.Add(output = new Event(this, eventName, target, MakeListener(target, method, true))); - return output; - } - - /// - /// 创建事件监听器 - /// - /// 调用目标 - /// 调用方法 - /// 是否是通配符方法 - /// 事件监听器 - protected virtual Action MakeListener(object target, MethodInfo method, bool isWildcard = false) - { - return (eventName, payloads) => - { - container.Call(target, method, isWildcard - ? Arr.Merge(new object[] { method }, payloads) - : payloads); - }; - } - - /// - /// 格式化事件名 - /// - /// 事件名 - /// 格式化后的事件名 - protected virtual string FormatEventName(string eventName) - { - return eventName; - } - } -} From 61d1721d960dc7c7a9152329997b0d4c3a8279b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Fri, 15 Dec 2017 17:41:48 +0800 Subject: [PATCH 62/91] event rebuild --- .../CatLib.Core.NetStandard.csproj | 5 +- .../CatLib/ApplicationTests.cs | 4 +- .../Support/Container/ContainerTests.cs | 6 +- .../Support/Dispatcher/DispatcherTests.cs | 172 +++--------------- src/CatLib.Core/CatLib.Core.csproj | 8 +- src/CatLib.Core/CatLib/App.cs | 89 +++++---- .../Support/Container/Container.cs | 43 ++++- src/CatLib.Core/Support/Events/Dispatcher.cs | 2 +- .../Support/Events/DispatcherExtend.cs | 13 ++ 9 files changed, 131 insertions(+), 211 deletions(-) diff --git a/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj b/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj index 5eada51..3a684e2 100644 --- a/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj +++ b/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj @@ -80,9 +80,10 @@ - + + - + diff --git a/src/CatLib.Core.Tests/CatLib/ApplicationTests.cs b/src/CatLib.Core.Tests/CatLib/ApplicationTests.cs index 56185ed..d422755 100644 --- a/src/CatLib.Core.Tests/CatLib/ApplicationTests.cs +++ b/src/CatLib.Core.Tests/CatLib/ApplicationTests.cs @@ -131,7 +131,7 @@ public void TestOn() var app = new Application(); ExceptionAssert.DoesNotThrow(() => { - app.On("hello", (o) => { }); + app.On("hello", () => { }); }); } @@ -309,7 +309,7 @@ public void TestOnDispatcher() { var app = MakeApplication(); - app.Listen("testevent", (payload) => + app.Listen("testevent", (object payload) => { Assert.AreEqual("abc", payload); return 123; diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs index 66a4bb3..b6840cd 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs @@ -691,12 +691,12 @@ public void TestLooseParameters() container.Bind(); var objOut = new object(); - var call = container.Wrap((object obj, SimpleTestClass1 cls1, int num, SimpleTestClass2 cls2) => + var call = container.Wrap((object[] obj, SimpleTestClass1 cls1, SimpleTestClass2 cls2) => { - Assert.AreSame(objOut, obj); + Assert.AreSame(objOut, obj[0]); Assert.AreNotEqual(null, cls1); Assert.AreNotEqual(null, cls2); - Assert.AreEqual(100, num); + Assert.AreEqual((long)100, obj[1]); }, objOut, (long)100); call.Invoke(); diff --git a/src/CatLib.Core.Tests/Support/Dispatcher/DispatcherTests.cs b/src/CatLib.Core.Tests/Support/Dispatcher/DispatcherTests.cs index a9885b0..fdb237d 100644 --- a/src/CatLib.Core.Tests/Support/Dispatcher/DispatcherTests.cs +++ b/src/CatLib.Core.Tests/Support/Dispatcher/DispatcherTests.cs @@ -37,7 +37,7 @@ public void TestSimpleOnEvents() var dispatcher = app.Make(); var isCall = false; - dispatcher.On("event.name", (payload) => + dispatcher.On("event.name", (object payload) => { isCall = true; Assert.AreEqual(123, payload); @@ -59,13 +59,13 @@ public void TestTriggerReturnResult() var dispatcher = app.Make(); var isCall = false; - dispatcher.Listen("event.name", (payload) => + dispatcher.Listen("event.name", (object payload) => { isCall = true; Assert.AreEqual(123, payload); return 1; }); - dispatcher.Listen("event.name", (payload) => + dispatcher.Listen("event.name", (object payload) => { Assert.AreEqual(123, payload); return 2; @@ -85,23 +85,23 @@ public void TestAsteriskWildcard() var dispatcher = app.Make(); var isCall = false; - dispatcher.Listen("event.name", (payload) => + dispatcher.Listen("event.name", (object payload) => { isCall = true; Assert.AreEqual(123, payload); return 1; }); - dispatcher.Listen("event.name", (payload) => + dispatcher.Listen("event.name", ( object payload) => { Assert.AreEqual(123, payload); return 2; }); - dispatcher.Listen("event.age", (payload) => + dispatcher.Listen("event.age", (object payload) => { Assert.AreEqual(123, payload); return 2; }); - dispatcher.Listen("event.*", (payload) => + dispatcher.Listen("event.*", (string eventName, object payload) => { Assert.AreEqual(123, payload); return 3; @@ -125,19 +125,19 @@ public void TestHalfTrigger() var dispatcher = app.Make(); var isCall = false; - dispatcher.Listen("event.name", (payload) => + dispatcher.Listen("event.name", (object payload) => { isCall = true; Assert.AreEqual(123, payload); return 1; }); - dispatcher.Listen("event.name", (payload) => + dispatcher.Listen("event.name", (object payload) => { isCall = true; Assert.AreEqual(123, payload); return 2; }); - dispatcher.Listen("event.*", (payload) => + dispatcher.Listen("event.*", (string eventName, object payload) => { Assert.AreEqual(123, payload); return 3; @@ -154,186 +154,56 @@ public void TestCancelHandler() var dispatcher = app.Make(); var isCall = false; - var handler = dispatcher.Listen("event.name", (payload) => + var handler = dispatcher.Listen("event.name", (object payload) => { isCall = true; Assert.AreEqual(123, payload); return 1; }); - dispatcher.Listen("event.name", (payload) => + dispatcher.Listen("event.name", (object payload) => { Assert.AreEqual(123, payload); return 2; }); - dispatcher.Listen("event.*", (payload) => + dispatcher.Listen("event.*", (string eventName, object payload) => { Assert.AreEqual(123, payload); return 3; }); - handler.Off(); + App.Off(handler); Assert.AreEqual(2, dispatcher.TriggerHalt("event.name", 123)); Assert.AreEqual(false, isCall); } - [TestMethod] - public void TestLifeCall() - { - var app = MakeEnv(); - - var dispatcher = app.Make(); - var isCall = false; - dispatcher.Listen("event.name", (payload) => - { - isCall = true; - Assert.AreEqual(123, payload); - return 1; - }, 1); - - Assert.AreEqual(1, dispatcher.TriggerHalt("event.name", 123)); - Assert.AreEqual(null, dispatcher.TriggerHalt("event.name", 123)); - Assert.AreEqual(true, isCall); - } - - [TestMethod] - public void TestDepthSelfTrigger() - { - var app = MakeEnv(); - - var dispatcher = app.Make(); - var callNum = 0; - dispatcher.Listen("event.name", (payload) => - { - dispatcher.Trigger("event.name", payload); - callNum++; - Assert.AreEqual(123, payload); - return 1; - }, 3); - - Assert.AreEqual(1, (dispatcher.Trigger("event.name", 123) as object[]).Length); - Assert.AreEqual(3, callNum); - - Assert.AreEqual(null, dispatcher.TriggerHalt("event.name", 123)); - } - - [TestMethod] - public void TestOrderCancel() - { - var app = MakeEnv(); - - var dispatcher = app.Make(); - dispatcher.Listen("event.name", (payload) => - { - Assert.AreEqual(123, payload); - return 1; - }, 1); - dispatcher.Listen("event.name", (payload) => - { - Assert.AreEqual(123, payload); - return 2; - }, 1); - dispatcher.Listen("event.*", (payload) => - { - Assert.AreEqual(123, payload); - return 3; - }, 1); - - Assert.AreEqual(1, dispatcher.TriggerHalt("event.name", 123)); - Assert.AreEqual(2, dispatcher.TriggerHalt("event.name", 123)); - Assert.AreEqual(3, dispatcher.TriggerHalt("event.name", 123)); - Assert.AreEqual(null, dispatcher.TriggerHalt("event.name", 123)); - } - - [TestMethod] - public void TestRepeatOn() - { - var app = MakeEnv(); - - var dispatcher = app.Make(); - dispatcher.Listen("event.*", (payload) => - { - Assert.AreEqual(123, payload); - return 1; - }, 1); - - dispatcher.Listen("event.*", (payload) => - { - Assert.AreEqual(123, payload); - return 2; - }, 1); - - Assert.AreEqual(1, dispatcher.TriggerHalt("event.name", 123)); - Assert.AreEqual(2, dispatcher.TriggerHalt("event.name", 123)); - Assert.AreEqual(null, dispatcher.TriggerHalt("event.name", 123)); - } - - [TestMethod] - public void TestOtherWildcardOn() - { - var app = MakeEnv(); - - var dispatcher = app.Make(); - dispatcher.Listen("event.*", (payload) => - { - Assert.AreEqual(123, payload); - return 1; - }, 1); - - dispatcher.Listen("event.call.*", (payload) => - { - Assert.AreEqual(123, payload); - return 2; - }, 1); - - dispatcher.Listen("event2.call.*", (payload) => - { - Assert.AreEqual(123, payload); - return 3; - }, 1); - - Assert.AreEqual(1, dispatcher.TriggerHalt("event.call.name", 123)); - Assert.AreEqual(2, dispatcher.TriggerHalt("event.call.name", 123)); - Assert.AreEqual(null, dispatcher.TriggerHalt("event.call.name", 123)); - } - [TestMethod] public void TestStopBubbling() { var app = MakeEnv(); var dispatcher = app.Make(); - dispatcher.Listen("event.*", (payload) => + dispatcher.Listen("event.*", (string eventName, object payload) => { Assert.AreEqual(123, payload); return 1; }); - dispatcher.Listen("event.time", (payload) => + dispatcher.Listen("event.time", (object payload) => { Assert.AreEqual(123, payload); return 2; }); - dispatcher.Listen("event.time", (payload) => + dispatcher.Listen("event.time", (object payload) => { Assert.AreEqual(123, payload); - return false; - }, 1); - dispatcher.Listen("event.time", (payload) => - { - Assert.AreEqual(123, payload); - return 4; + return 3; }); var results = dispatcher.Trigger("event.time", 123); - Assert.AreEqual(1, results.Length); - Assert.AreEqual(2, results[0]); - - results = dispatcher.Trigger("event.time", 123); - Assert.AreEqual(3, results.Length); Assert.AreEqual(2, results[0]); - Assert.AreEqual(4, results[1]); + Assert.AreEqual(3, results[1]); Assert.AreEqual(1, results[2]); } @@ -343,13 +213,13 @@ public void TestHaltNull() var app = MakeEnv(); var dispatcher = app.Make(); - dispatcher.Listen("event.*", (payload) => + dispatcher.Listen("event.*", (string eventName, object payload) => { Assert.AreEqual(123, payload); return 1; }); - dispatcher.Listen("event.time", (payload) => + dispatcher.Listen("event.time", (object payload) => { Assert.AreEqual(123, payload); return null; diff --git a/src/CatLib.Core/CatLib.Core.csproj b/src/CatLib.Core/CatLib.Core.csproj index ad0815b..cb46ede 100644 --- a/src/CatLib.Core/CatLib.Core.csproj +++ b/src/CatLib.Core/CatLib.Core.csproj @@ -51,10 +51,9 @@ - - + - + @@ -66,7 +65,8 @@ - + + diff --git a/src/CatLib.Core/CatLib/App.cs b/src/CatLib.Core/CatLib/App.cs index 0253343..d32f9ed 100644 --- a/src/CatLib.Core/CatLib/App.cs +++ b/src/CatLib.Core/CatLib/App.cs @@ -175,7 +175,16 @@ public static object TriggerHalt(string eventName, params object[] payloads) return Handler.TriggerHalt(eventName, payloads); } - + /// + /// 注册一个事件监听器 + /// + /// 事件名称 + /// 事件处理方法 + /// 事件对象 + public static IEvent On(string eventName, Action method) + { + return Handler.On(eventName, method); + } /// /// 注册一个事件监听器 @@ -192,123 +201,125 @@ public static IEvent On(string eventName, object target, string method = null) /// /// 注册一个事件监听器 /// - /// 事件调度器 /// 事件名称 /// 事件处理方法 /// 事件对象 - public static IEvent On(this IDispatcher dispatcher, string eventName, Action method) + public static IEvent On(string eventName, Action method) { - Guard.Requires(method != null); - return dispatcher.On(eventName, method.Target, method.Method); + return Handler.On(eventName, method); } /// /// 注册一个事件监听器 /// - /// 事件调度器 /// 事件名称 /// 事件处理方法 /// 事件对象 - public static IEvent On(this IDispatcher dispatcher, string eventName, Action method) + public static IEvent On(string eventName, Action method) { - Guard.Requires(method != null); - return dispatcher.On(eventName, method.Target, method.Method); + return Handler.On(eventName, method); } /// /// 注册一个事件监听器 /// - /// 事件调度器 /// 事件名称 /// 事件处理方法 /// 事件对象 - public static IEvent On(this IDispatcher dispatcher, string eventName, Action method) + public static IEvent On(string eventName, Action method) { - Guard.Requires(method != null); - return dispatcher.On(eventName, method.Target, method.Method); + return Handler.On(eventName, method); } /// /// 注册一个事件监听器 /// - /// 事件调度器 /// 事件名称 /// 事件处理方法 /// 事件对象 - public static IEvent On(this IDispatcher dispatcher, string eventName, Action method) + public static IEvent On(string eventName, Action method) { - Guard.Requires(method != null); - return dispatcher.On(eventName, method.Target, method.Method); + return Handler.On(eventName, method); } /// /// 注册一个事件监听器 /// - /// 事件调度器 /// 事件名称 /// 事件处理方法 /// 事件对象 - public static IEvent Listen(this IDispatcher dispatcher, string eventName, Func method) + public static IEvent Listen(string eventName, Func method) { - Guard.Requires(method != null); - return dispatcher.On(eventName, method.Target, method.Method); + return Handler.On(eventName, method); } /// /// 注册一个事件监听器 /// - /// 事件调度器 /// 事件名称 /// 事件处理方法 /// 事件对象 - public static IEvent Listen(this IDispatcher dispatcher, string eventName, Func method) + public static IEvent Listen(string eventName, Func method) { - Guard.Requires(method != null); - return dispatcher.On(eventName, method.Target, method.Method); + return Handler.On(eventName, method); } /// /// 注册一个事件监听器 /// - /// 事件调度器 /// 事件名称 /// 事件处理方法 /// 事件对象 - public static IEvent Listen(this IDispatcher dispatcher, string eventName, Func method) + public static IEvent Listen(string eventName, Func method) { - Guard.Requires(method != null); - return dispatcher.On(eventName, method.Target, method.Method); + return Handler.On(eventName, method); } /// /// 注册一个事件监听器 /// - /// 事件调度器 /// 事件名称 /// 事件处理方法 /// 事件对象 - public static IEvent Listen(this IDispatcher dispatcher, string eventName, Func method) + public static IEvent Listen(string eventName, Func method) { - Guard.Requires(method != null); - return dispatcher.On(eventName, method.Target, method.Method); + return Handler.On(eventName, method); } /// /// 注册一个事件监听器 /// - /// 事件调度器 /// 事件名称 /// 事件处理方法 /// 事件对象 - public static IEvent Listen(this IDispatcher dispatcher, string eventName, Func method) + public static IEvent Listen(string eventName, Func method) { - Guard.Requires(method != null); - return dispatcher.On(eventName, method.Target, method.Method); + return Handler.On(eventName, method); } + /// + /// 判断给定事件是否存在事件监听器 + /// + /// 事件名 + /// 是否存在事件监听器 + public static bool HasListeners(string eventName) + { + return Handler.HasListeners(eventName); + } - - + /// + /// 解除注册的事件监听器 + /// + /// + /// 事件解除目标 + /// 如果传入的是字符串(string)将会解除对应事件名的所有事件 + /// 如果传入的是事件对象(IEvent)那么解除对应事件 + /// 如果传入的是其他实例(object)会解除该实例下的所有事件 + /// + public static void Off(object target) + { + Handler.Off(target); + } /// /// 获取服务的绑定数据,如果绑定不存在则返回null diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index fdce776..2ce512b 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -1168,18 +1168,43 @@ protected virtual void AttributeInject(Bindable makeServiceBindData, object make /// /// 检查是否可以紧缩注入用户传入的参数 /// - /// 服务实例的参数信息 + /// 服务实例的参数信息 /// 输入的构造参数列表 /// 是否可以紧缩注入 - protected virtual bool CheckCompactInjectUserParams(ParameterInfo baseParams, object[] userParams) + protected virtual bool CheckCompactInjectUserParams(ParameterInfo baseParam, object[] userParams) { - if (userParams.Length <= 0) + if (userParams == null || userParams.Length <= 0) { return false; } - return baseParams.GetType() == typeof(object[]) - || baseParams.GetType() == typeof(object); + return baseParam.ParameterType == typeof(object[]) + || baseParam.ParameterType == typeof(object); + } + + /// + /// 获取通过紧缩注入的参数 + /// + /// 服务实例的参数信息 + /// 输入的构造参数列表 + /// 紧缩注入的参数 + protected virtual object GetCompactInjectUserParams(ParameterInfo baseParam, ref object[] userParams) + { + if (!CheckCompactInjectUserParams(baseParam, userParams)) + { + return null; + } + + var result = userParams; + userParams = null; + + if (baseParam.ParameterType == typeof(object) + && result != null && result.Length == 1) + { + return result[0]; + } + + return result; } /// @@ -1198,15 +1223,15 @@ protected virtual object[] GetDependencies(Bindable makeServiceBindData, Paramet { // 当容器发现开发者使用 object 或者 object[] 作为参数类型时 // 我们尝试将所有用户传入的用户参数紧缩注入 - if (CheckCompactInjectUserParams(baseParam, userParams)) + var param = GetCompactInjectUserParams(baseParam, ref userParams); + if (param != null) { - results.Add(userParams); - userParams = null; + results.Add(param); continue; } // 从用户传入的参数中挑选合适的参数,按照相对顺序依次注入 - var param = GetDependenciesFromUserParams(baseParam, ref userParams); + param = GetDependenciesFromUserParams(baseParam, ref userParams); if (param != null) { results.Add(param); diff --git a/src/CatLib.Core/Support/Events/Dispatcher.cs b/src/CatLib.Core/Support/Events/Dispatcher.cs index a858d6e..f260e26 100644 --- a/src/CatLib.Core/Support/Events/Dispatcher.cs +++ b/src/CatLib.Core/Support/Events/Dispatcher.cs @@ -209,7 +209,7 @@ protected virtual IEvent MakeEvent(string eventName, object target, MethodInfo m protected virtual Func MakeListener(object target, MethodInfo method, bool isWildcard = false) { return (eventName, payloads) => container.Call(target, method, isWildcard - ? Arr.Merge(new object[] { method }, payloads) + ? Arr.Merge(new object[] { eventName }, payloads) : payloads); } diff --git a/src/CatLib.Core/Support/Events/DispatcherExtend.cs b/src/CatLib.Core/Support/Events/DispatcherExtend.cs index 82a783d..ba8ec86 100644 --- a/src/CatLib.Core/Support/Events/DispatcherExtend.cs +++ b/src/CatLib.Core/Support/Events/DispatcherExtend.cs @@ -35,6 +35,19 @@ public static IEvent On(this IDispatcher dispatcher, string eventName, object ta return dispatcher.On(eventName, target, target.GetType().GetMethod(method ?? Str.Method(eventName))); } + /// + /// 注册一个事件监听器 + /// + /// 事件调度器 + /// 事件名称 + /// 事件处理方法 + /// 事件对象 + public static IEvent On(this IDispatcher dispatcher, string eventName, Action method) + { + Guard.Requires(method != null); + return dispatcher.On(eventName, method.Target, method.Method); + } + /// /// 注册一个事件监听器 /// From 783e7977d5cb2c8a1871f653ac76848c5767a9e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Fri, 15 Dec 2017 19:00:39 +0800 Subject: [PATCH 63/91] events add unit test --- .../Support/Dispatcher/DispatcherTests.cs | 214 ++++++++++++++++++ src/CatLib.Core/CatLib/App.cs | 18 +- src/CatLib.Core/CatLib/Application.cs | 8 +- src/CatLib.Core/Support/Events/Dispatcher.cs | 31 ++- src/CatLib.Core/Support/Events/Event.cs | 5 +- src/CatLib.Core/Support/Events/IDispatcher.cs | 6 +- src/CatLib.Core/Support/Events/IEvent.cs | 3 +- 7 files changed, 267 insertions(+), 18 deletions(-) diff --git a/src/CatLib.Core.Tests/Support/Dispatcher/DispatcherTests.cs b/src/CatLib.Core.Tests/Support/Dispatcher/DispatcherTests.cs index fdb237d..d8f2463 100644 --- a/src/CatLib.Core.Tests/Support/Dispatcher/DispatcherTests.cs +++ b/src/CatLib.Core.Tests/Support/Dispatcher/DispatcherTests.cs @@ -227,5 +227,219 @@ public void TestHaltNull() Assert.AreEqual(1, dispatcher.TriggerHalt("event.time", 123)); } + + [TestMethod] + public void TestBreakEvent() + { + var app = MakeEnv(); + + var dispatcher = app.Make(); + dispatcher.Listen("event.time", (object payload) => + { + Assert.AreEqual(123, payload); + return 1; + }); + + dispatcher.Listen("event.time", (object payload) => + { + Assert.AreEqual(123, payload); + return false; + }); + + dispatcher.Listen("event.time", (object payload) => + { + Assert.AreEqual(123, payload); + return 2; + }); + + var result = dispatcher.Trigger("event.time", 123); + Assert.AreEqual(1, result.Length); + Assert.AreEqual(1, result[0]); + } + + [TestMethod] + public void TestAllHaltNull() + { + var app = MakeEnv(); + + var dispatcher = app.Make(); + dispatcher.Listen("event.time", (object payload) => + { + return null; + }); + + dispatcher.Listen("event.time", (object payload) => + { + return null; + }); + + Assert.AreEqual(null, dispatcher.TriggerHalt("event.time")); + } + + [TestMethod] + public void TestOffWithEventName() + { + var app = MakeEnv(); + var dispatcher = app.Make(); + var handler = dispatcher.Listen("event.time", (object payload) => + { + return 1; + }); + + dispatcher.Listen("event.time", (object payload) => + { + return 1; + }); + + var handler2 = dispatcher.Listen("event.*", (object payload) => + { + return 1; + }); + + App.Off("event.time"); + App.Off("event.time"); // double remove + App.Off("event.*"); + App.Off("event.*.Empty"); + App.Off(handler); + App.Off(handler2); + + Assert.AreEqual(0, dispatcher.Trigger("event.time").Length); + } + + public class TestEventClass + { + public object TestFuncHello() + { + return "hello"; + } + + public object TestFuncWorld(IContainer container) + { + Assert.AreNotEqual(null, container); + return "world"; + } + } + + [TestMethod] + public void TestOffWithObject() + { + var app = MakeEnv(); + var dispatcher = app.Make(); + + var cls = new TestEventClass(); + dispatcher.On("MyTestEventClass.TestFuncHello", cls); + dispatcher.On("MyTestEventClass.*", cls, "TestFuncWorld"); + + Assert.AreEqual("hello", dispatcher.TriggerHalt("MyTestEventClass.TestFuncHello")); + Assert.AreEqual("world", dispatcher.TriggerHalt("MyTestEventClass.Jump")); + + App.Off(cls); + App.Off(cls); // double off + + Assert.AreEqual(null, dispatcher.TriggerHalt("MyTestEventClass.TestFuncHello")); + Assert.AreEqual(null, dispatcher.TriggerHalt("MyTestEventClass.Jump")); + } + + [TestMethod] + public void TestHasListeners() + { + var app = MakeEnv(); + var dispatcher = app.Make(); + + var cls = new TestEventClass(); + dispatcher.On("MyTestEventClass.TestFuncHello", cls); + dispatcher.On("MyTestEventClass.*", cls, "TestFuncWorld"); + var isCall = false; + dispatcher.On("MyTestEventClass.*", (string name) => + { + isCall = true; + Assert.AreEqual("MyTestEventClass.Jump.Hack", name); + }); + + Assert.AreEqual(false, App.HasListeners("Null")); + Assert.AreEqual(true, App.HasListeners("MyTestEventClass.TestFuncHello")); + Assert.AreEqual(true, App.HasListeners("MyTestEventClass.Jump.Hack")); + Assert.AreEqual(false, App.HasListeners("MyTestEventClass.Jump.Hack", true)); + App.Trigger("MyTestEventClass.Jump.Hack"); + Assert.AreEqual(true, isCall); + } + + [TestMethod] + public void TestActionFuncCover() + { + var app = MakeEnv(); + var dispatcher = app.Make(); + + App.On("ActionTest", () => + { + }); + + App.On("ActionTest", (IContainer container) => + { + Assert.AreNotEqual(null, container); + }); + + App.On("ActionTest", (IContainer container, object data) => + { + Assert.AreEqual(typeof(string), data.GetType()); + Assert.AreNotEqual(null, container); + }); + + App.On("ActionTest2", (int num, int num2 ,int num3) => + { + Assert.AreEqual(1, num); + Assert.AreEqual(2, num2); + Assert.AreEqual(3, num3); + }); + + App.On("ActionTest2", (int num, int num2, int num3, int num4) => + { + Assert.AreEqual(1, num); + Assert.AreEqual(2, num2); + Assert.AreEqual(3, num3); + Assert.AreEqual(4, num4); + }); + + App.Trigger("ActionTest", "helloworld"); + App.Trigger("ActionTest2", 1, 2, 3, 4); + + App.Listen("FuncTest", () => + { + return 0; + }); + + App.Listen("FuncTest", (IContainer container) => + { + Assert.AreNotEqual(null, container); + return 1; + }); + + App.Listen("FuncTest", (IContainer container, object data) => + { + Assert.AreEqual(typeof(string), data.GetType()); + Assert.AreNotEqual(null, container); + return 2; + }); + + App.Listen("FuncTest2", (int num, int num2, int num3) => + { + Assert.AreEqual(1, num); + Assert.AreEqual(2, num2); + Assert.AreEqual(3, num3); + return 3; + }); + + App.Listen("FuncTest2", (int num, int num2, int num3, int num4) => + { + Assert.AreEqual(1, num); + Assert.AreEqual(2, num2); + Assert.AreEqual(3, num3); + Assert.AreEqual(4, num4); + return 4; + }); + + Assert.AreEqual(3, App.Trigger("FuncTest", "helloworld").Length); + Assert.AreEqual(2, App.Trigger("FuncTest2", 1, 2, 3, 4).Length); + } } } diff --git a/src/CatLib.Core/CatLib/App.cs b/src/CatLib.Core/CatLib/App.cs index d32f9ed..c629fca 100644 --- a/src/CatLib.Core/CatLib/App.cs +++ b/src/CatLib.Core/CatLib/App.cs @@ -250,7 +250,7 @@ public static IEvent On(string eventName, Action /// 事件对象 public static IEvent Listen(string eventName, Func method) { - return Handler.On(eventName, method); + return Handler.Listen(eventName, method); } /// @@ -261,7 +261,7 @@ public static IEvent Listen(string eventName, Func method) /// 事件对象 public static IEvent Listen(string eventName, Func method) { - return Handler.On(eventName, method); + return Handler.Listen(eventName, method); } /// @@ -272,7 +272,7 @@ public static IEvent Listen(string eventName, Func method) /// 事件对象 public static IEvent Listen(string eventName, Func method) { - return Handler.On(eventName, method); + return Handler.Listen(eventName, method); } /// @@ -283,7 +283,7 @@ public static IEvent Listen(string eventName, Func metho /// 事件对象 public static IEvent Listen(string eventName, Func method) { - return Handler.On(eventName, method); + return Handler.Listen(eventName, method); } /// @@ -294,17 +294,21 @@ public static IEvent Listen(string eventName, Func事件对象 public static IEvent Listen(string eventName, Func method) { - return Handler.On(eventName, method); + return Handler.Listen(eventName, method); } /// /// 判断给定事件是否存在事件监听器 /// /// 事件名 + /// + /// 严格模式 + /// 启用严格模式则不使用正则来进行匹配事件监听器 + /// /// 是否存在事件监听器 - public static bool HasListeners(string eventName) + public static bool HasListeners(string eventName, bool strict = false) { - return Handler.HasListeners(eventName); + return Handler.HasListeners(eventName, strict); } /// diff --git a/src/CatLib.Core/CatLib/Application.cs b/src/CatLib.Core/CatLib/Application.cs index 84e6b74..91c5cc4 100644 --- a/src/CatLib.Core/CatLib/Application.cs +++ b/src/CatLib.Core/CatLib/Application.cs @@ -307,10 +307,14 @@ public object TriggerHalt(string eventName, params object[] payloads) /// 判断给定事件是否存在事件监听器 /// /// 事件名 + /// + /// 严格模式 + /// 启用严格模式则不使用正则来进行匹配事件监听器 + /// /// 是否存在事件监听器 - public bool HasListeners(string eventName) + public bool HasListeners(string eventName, bool strict = false) { - return Dispatcher.HasListeners(eventName); + return Dispatcher.HasListeners(eventName, strict); } /// diff --git a/src/CatLib.Core/Support/Events/Dispatcher.cs b/src/CatLib.Core/Support/Events/Dispatcher.cs index f260e26..3808652 100644 --- a/src/CatLib.Core/Support/Events/Dispatcher.cs +++ b/src/CatLib.Core/Support/Events/Dispatcher.cs @@ -81,15 +81,36 @@ public Dispatcher(IContainer container) /// 判断给定事件是否存在事件监听器 /// /// 事件名 + /// + /// 严格模式 + /// 启用严格模式则不使用正则来进行匹配事件监听器 + /// /// 是否存在事件监听器 - public bool HasListeners(string eventName) + public bool HasListeners(string eventName, bool strict = false) { eventName = FormatEventName(eventName); lock (syncRoot) { - return IsWildcard(eventName) - ? wildcardListeners.ContainsKey(eventName) - : listeners.ContainsKey(eventName); + if (listeners.ContainsKey(eventName) + || wildcardListeners.ContainsKey(eventName)) + { + return true; + } + + if (strict) + { + return false; + } + + foreach (var element in wildcardListeners) + { + if (element.Value.Key.IsMatch(eventName)) + { + return true; + } + } + + return false; } } @@ -241,7 +262,7 @@ private object Dispatch(bool halt, string eventName, params object[] payload) foreach (var listener in GetListeners(eventName)) { - var response = listener.Call(payload); + var response = listener.Call(eventName, payload); // 如果启用了事件暂停,且得到的有效的响应那么我们终止事件调用 if (halt && response != null) diff --git a/src/CatLib.Core/Support/Events/Event.cs b/src/CatLib.Core/Support/Events/Event.cs index 750b729..21227ea 100644 --- a/src/CatLib.Core/Support/Events/Event.cs +++ b/src/CatLib.Core/Support/Events/Event.cs @@ -57,10 +57,11 @@ public Event(string eventName, object target, MethodInfo method, Func /// 调用事件 /// + /// 事件名 /// 载荷 - public object Call(params object[] payloads) + public object Call(string eventName, params object[] payloads) { - return transfer(EventName, payloads); + return transfer(eventName, payloads); } } } diff --git a/src/CatLib.Core/Support/Events/IDispatcher.cs b/src/CatLib.Core/Support/Events/IDispatcher.cs index d50f4ff..26ebb53 100644 --- a/src/CatLib.Core/Support/Events/IDispatcher.cs +++ b/src/CatLib.Core/Support/Events/IDispatcher.cs @@ -23,8 +23,12 @@ public interface IDispatcher /// 判断给定事件是否存在事件监听器 /// /// 事件名 + /// + /// 严格模式 + /// 启用严格模式则不使用正则来进行匹配事件监听器 + /// /// 是否存在事件监听器 - bool HasListeners(string eventName); + bool HasListeners(string eventName, bool strict = false); /// /// 触发一个事件,并获取事件监听器的返回结果 diff --git a/src/CatLib.Core/Support/Events/IEvent.cs b/src/CatLib.Core/Support/Events/IEvent.cs index 5d273b1..a29a1b3 100644 --- a/src/CatLib.Core/Support/Events/IEvent.cs +++ b/src/CatLib.Core/Support/Events/IEvent.cs @@ -36,8 +36,9 @@ public interface IEvent /// /// 调用事件 /// + /// 事件名 /// 载荷 /// 事件结果 - object Call(params object[] payloads); + object Call(string eventName, params object[] payloads); } } From f2d60576866eb791b923531c4e76e5cfdf8db97a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Sat, 16 Dec 2017 17:53:35 +0800 Subject: [PATCH 64/91] container update --- .../Support/Container/ContainerTests.cs | 3 --- src/CatLib.Core/CatLib/App.cs | 11 ----------- src/CatLib.Core/Support/Container/ContainerExtend.cs | 12 ------------ 3 files changed, 26 deletions(-) diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs index b6840cd..92264d1 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs @@ -569,9 +569,6 @@ public void TestFactory() var fac = container.Factory(); Assert.AreEqual(container.Make(), fac.Invoke()); - - var fac2 = container.Factory("hello"); - Assert.AreEqual(123, fac2.Invoke()); } [TestMethod] diff --git a/src/CatLib.Core/CatLib/App.cs b/src/CatLib.Core/CatLib/App.cs index c629fca..f79290f 100644 --- a/src/CatLib.Core/CatLib/App.cs +++ b/src/CatLib.Core/CatLib/App.cs @@ -619,17 +619,6 @@ public static Func Factory() return Handler.Factory(); } - /// - /// 获取一个回调,当执行回调可以生成指定的服务 - /// - /// 服务名 - /// 服务名或者别名 - /// 回调方案 - public static Func Factory(string service) - { - return Handler.Factory(service); - } - /// /// 为服务设定一个别名 /// diff --git a/src/CatLib.Core/Support/Container/ContainerExtend.cs b/src/CatLib.Core/Support/Container/ContainerExtend.cs index 09a75d0..2d27955 100644 --- a/src/CatLib.Core/Support/Container/ContainerExtend.cs +++ b/src/CatLib.Core/Support/Container/ContainerExtend.cs @@ -491,18 +491,6 @@ public static Func Factory(this IContainer container) return () => (TService)container.Factory(container.Type2Service(typeof(TService))).Invoke(); } - /// - /// 获取一个回调,当执行回调可以生成指定的服务 - /// - /// 服务名 - /// 服务容器 - /// 服务名或者别名 - /// 回调方案 - public static Func Factory(this IContainer container, string service) - { - return () => (TService)container.Factory(service).Invoke(); - } - /// /// 释放服务 /// From e43e52e7636c4e30b43f356c480cea7f349be191 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Sun, 17 Dec 2017 20:04:22 +0800 Subject: [PATCH 65/91] container update --- .../Support/Container/Container.cs | 24 +++++++++---------- src/CatLib.Core/Support/Util/Dict.cs | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 2ce512b..c0568a5 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -1262,18 +1262,6 @@ protected virtual object[] GetDependencies(Bindable makeServiceBindData, Paramet return results.ToArray(); } - /// - /// 获取别名最终对应的服务名 - /// - /// 服务名或别名 - /// 最终映射的服务名 - protected virtual string AliasToService(string service) - { - service = FormatService(service); - string alias; - return aliases.TryGetValue(service, out alias) ? alias : service; - } - /// /// 获取构造函数参数 /// @@ -1315,6 +1303,18 @@ protected virtual object[] GetConstructorsInjectParams(Bindable makeServiceBindD throw exception; } + /// + /// 获取别名最终对应的服务名 + /// + /// 服务名或别名 + /// 最终映射的服务名 + private string AliasToService(string service) + { + service = FormatService(service); + string alias; + return aliases.TryGetValue(service, out alias) ? alias : service; + } + /// /// 触发全局解决修饰器 /// diff --git a/src/CatLib.Core/Support/Util/Dict.cs b/src/CatLib.Core/Support/Util/Dict.cs index aa17d42..82ca6ea 100644 --- a/src/CatLib.Core/Support/Util/Dict.cs +++ b/src/CatLib.Core/Support/Util/Dict.cs @@ -102,7 +102,7 @@ public static void Modify(IDictionary source, Func - /// 批量添加到字典 + /// 将元素批量添加到字典 /// /// 字典键 /// 字典值 @@ -233,7 +233,7 @@ public static void Set(IDictionary dict, string key, object val) } /// - /// 使用点(.)来访问深度字典,并移除其中一个值 + /// 使用点(.)来访问深度字典,并移除其中指定的值 /// /// 规定字典 /// 键,支持使用点(.)来进行深度访问 From 191d2c555ef2ab20ebbcdaaeab637d21f148e7e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Wed, 20 Dec 2017 14:28:17 +0800 Subject: [PATCH 66/91] container update --- .../Support/Container/ContainerHelperTests.cs | 57 +- .../Support/Container/ContainerTests.cs | 2 +- src/CatLib.Core/CatLib/App.cs | 552 +++++++++++------- .../Support/Container/Container.cs | 10 +- .../Support/Container/ContainerExtend.cs | 469 +++++++++------ .../Support/Container/IContainer.cs | 12 +- 6 files changed, 697 insertions(+), 405 deletions(-) diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerHelperTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerHelperTests.cs index 160daee..6582b4a 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerHelperTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerHelperTests.cs @@ -134,7 +134,9 @@ public void TestBindIf() Assert.AreEqual(true, App.BindIf(out bindData)); Assert.AreEqual(typeof(object), app.Make().GetType()); - Assert.AreEqual(true, App.BindIf((c, p) => 100, out bindData)); + Assert.AreEqual(true, App.BindIf((c,p) => 100, out bindData)); + Assert.AreEqual(true, App.BindIf(() => 100, out bindData)); + Assert.AreEqual(100, App.Make()); Assert.AreEqual(true, App.BindIf(out bindData)); Assert.AreEqual(false, App.BindIf(out bindData)); @@ -158,13 +160,64 @@ public void TestSingletonIf() Assert.AreEqual(true, App.SingletonIf(out bindData)); Assert.AreEqual(typeof(object), app.Make().GetType()); - Assert.AreEqual(true, App.SingletonIf((c, p) => 100, out bindData)); + Assert.AreEqual(true, App.SingletonIf((c, p) => 100, out bindData)); + Assert.AreEqual(true, App.SingletonIf(() => 100, out bindData)); + Assert.AreEqual(100, App.Make()); Assert.AreEqual(true, App.SingletonIf(out bindData)); Assert.AreEqual(false, App.SingletonIf(out bindData)); Assert.AreEqual(typeof(double), App.Make(App.Type2Service(typeof(float))).GetType()); } + [TestMethod] + public void TestGetBind() + { + var container = new Container(); + var bind = container.Bind(() => "helloworld"); + + Assert.AreEqual("helloworld", container.Make(container.Type2Service())); + Assert.AreEqual(true, container.HasBind()); + Assert.AreSame(bind, container.GetBind()); + } + + [TestMethod] + public void TestCanMake() + { + var container = new Container(); + + Assert.AreEqual(false, container.CanMake()); + container.Bind(() => "helloworld"); + Assert.AreEqual(true, container.CanMake()); + } + + [TestMethod] + public void TestIsStatic() + { + var container = new Container(); + container.Bind(() => "helloworld"); + Assert.AreEqual(false, container.IsStatic()); + container.Unbind(); + container.Singleton(() => "helloworld"); + Assert.AreEqual("helloworld", container.Make(container.Type2Service())); + Assert.AreEqual(true, container.IsStatic()); + } + + [TestMethod] + public void TestIsAlias() + { + var container = new Container(); + container.Bind(() => "helloworld").Alias(); + Assert.AreEqual(false, container.IsAlias()); + Assert.AreEqual(true, container.IsAlias()); + } + + [TestMethod] + public void TestGetService() + { + var container = new Container(); + Assert.AreEqual(container.Type2Service(typeof(string)), container.Type2Service()); + } + /// /// 生成容器 /// diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs index 92264d1..d017821 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs @@ -576,7 +576,7 @@ public void TestIsAlias() { var container = MakeContainer(); container.Instance(container); - container.Alias("123"); + container.Alias("123", container.Type2Service()); Assert.AreEqual(true, container.IsAlias("123")); Assert.AreEqual(false, container.IsAlias(container.Type2Service(typeof(Container)))); diff --git a/src/CatLib.Core/CatLib/App.cs b/src/CatLib.Core/CatLib/App.cs index f79290f..d7b99e7 100644 --- a/src/CatLib.Core/CatLib/App.cs +++ b/src/CatLib.Core/CatLib/App.cs @@ -21,6 +21,7 @@ namespace CatLib [ExcludeFromCodeCoverage] public static class App { + #region Original /// /// 当新建Application时 /// @@ -53,7 +54,9 @@ public static IApplication Handler } } } + #endregion + #region Application API /// /// 注册服务提供者 /// @@ -152,6 +155,22 @@ public static DebugLevels DebugLevel get { return Handler.DebugLevel; } set { Handler.DebugLevel = value; } } + #endregion + + #region Dispatcher API + /// + /// 判断给定事件是否存在事件监听器 + /// + /// 事件名 + /// + /// 严格模式 + /// 启用严格模式则不使用正则来进行匹配事件监听器 + /// + /// 是否存在事件监听器 + public static bool HasListeners(string eventName, bool strict = false) + { + return Handler.HasListeners(eventName, strict); + } /// /// 触发一个事件,并获取事件的返回结果 @@ -297,20 +316,6 @@ public static IEvent Listen(string eventName, Func - /// 判断给定事件是否存在事件监听器 - /// - /// 事件名 - /// - /// 严格模式 - /// 启用严格模式则不使用正则来进行匹配事件监听器 - /// - /// 是否存在事件监听器 - public static bool HasListeners(string eventName, bool strict = false) - { - return Handler.HasListeners(eventName, strict); - } - /// /// 解除注册的事件监听器 /// @@ -324,7 +329,9 @@ public static void Off(object target) { Handler.Off(target); } + #endregion + #region Container API /// /// 获取服务的绑定数据,如果绑定不存在则返回null /// @@ -379,10 +386,10 @@ public static bool IsAlias(string name) /// 绑定一个服务 /// /// 服务名 - /// 服务实体 + /// 服务实现 /// 服务是否静态化 /// 服务绑定数据 - public static IBindData Bind(string service, Func concrete, bool isStatic) + public static IBindData Bind(string service, Type concrete, bool isStatic) { return Handler.Bind(service, concrete, isStatic); } @@ -391,10 +398,10 @@ public static IBindData Bind(string service, Func /// 绑定一个服务 /// /// 服务名 - /// 服务实现 + /// 服务实体 /// 服务是否静态化 /// 服务绑定数据 - public static IBindData Bind(string service, Type concrete, bool isStatic) + public static IBindData Bind(string service, Func concrete, bool isStatic) { return Handler.Bind(service, concrete, isStatic); } @@ -425,6 +432,41 @@ public static bool BindIf(string service, Type concrete, bool isStatic, out IBin return Handler.BindIf(service, concrete, isStatic, out bindData); } + /// + /// 绑定一个方法到容器 + /// + /// 方法名 + /// 调用目标 + /// 调用方法 + /// 方法绑定数据 + public static IMethodBind BindMethod(string method, object target, MethodInfo call) + { + return Handler.BindMethod(method, target, call); + } + + /// + /// 解除绑定的方法 + /// + /// + /// 解除目标 + /// 如果为字符串则作为调用方法名 + /// 如果为IMethodBind则作为指定方法 + /// 如果为其他对象则作为调用目标做全体解除 + /// + public static void UnbindMethod(object target) + { + Handler.UnbindMethod(target); + } + + /// + /// 解除绑定服务 + /// + /// 服务名或者别名 + public static void Unbind(string service) + { + Handler.Unbind(service); + } + /// /// 为一个及以上的服务定义一个标记 /// @@ -464,15 +506,6 @@ public static void Release(string service) Handler.Release(service); } - /// - /// 当静态服务被释放时 - /// - /// 处理释放时的回调 - public static IContainer OnRelease(Action action) - { - return Handler.OnRelease(action); - } - /// /// 调用一个已经被绑定的方法 /// @@ -484,18 +517,6 @@ public static object Invoke(string method, params object[] userParams) return Handler.Invoke(method, userParams); } - /// - /// 以依赖注入形式调用一个方法 - /// - /// 方法对象 - /// 方法名 - /// 用户传入的参数 - /// 方法返回值 - public static object Call(object instance, string method, params object[] userParams) - { - return Handler.Call(instance, method, userParams); - } - /// /// 以依赖注入形式调用一个方法 /// @@ -508,86 +529,6 @@ public static object Call(object instance, MethodInfo methodInfo, params object[ return Handler.Call(instance, methodInfo, userParams); } - /// - /// 以依赖注入的形式调用一个方法 - /// - /// 方法 - public static void Call(Action method) - { - Handler.Call(method); - } - - /// - /// 以依赖注入的形式调用一个方法 - /// - /// 方法 - public static void Call(Action method) - { - Handler.Call(method); - } - - /// - /// 以依赖注入的形式调用一个方法 - /// - /// 方法 - public static void Call(Action method) - { - Handler.Call(method); - } - - /// - /// 以依赖注入的形式调用一个方法 - /// - /// 方法 - public static void Call(Action method) - { - Handler.Call(method); - } - - /// - /// 包装一个依赖注入形式调用的一个方法 - /// - /// 方法 - /// 用户传入的参数 - /// 包装方法 - public static Action Wrap(Action method, params object[] userParams) - { - return Handler.Wrap(method, userParams); - } - - /// - /// 包装一个依赖注入形式调用的一个方法 - /// - /// 方法 - /// 用户传入的参数 - /// 包装方法 - public static Action Wrap(Action method, params object[] userParams) - { - return Handler.Wrap(method, userParams); - } - - /// - /// 包装一个依赖注入形式调用的一个方法 - /// - /// 方法 - /// 用户传入的参数 - /// 包装方法 - public static Action Wrap(Action method, params object[] userParams) - { - return Handler.Wrap(method, userParams); - } - - /// - /// 包装一个依赖注入形式调用的一个方法 - /// - /// 方法 - /// 用户传入的参数 - /// 包装方法 - public static Action Wrap(Action method, params object[] userParams) - { - return Handler.Wrap(method, userParams); - } - /// /// 构造服务 /// @@ -609,16 +550,6 @@ public static Func Factory(string service) return Handler.Factory(service); } - /// - /// 获取一个回调,当执行回调可以生成指定的服务 - /// - /// 服务名 - /// 回调方案 - public static Func Factory() - { - return Handler.Factory(); - } - /// /// 为服务设定一个别名 /// @@ -640,6 +571,15 @@ public static IContainer OnResolving(Func func) return Handler.OnResolving(func); } + /// + /// 当静态服务被释放时 + /// + /// 处理释放时的回调 + public static IContainer OnRelease(Action action) + { + return Handler.OnRelease(action); + } + /// /// 当查找类型无法找到时会尝试去调用开发者提供的查找类型函数 /// @@ -675,6 +615,16 @@ public static void Watch(string service, object target, MethodInfo methodInfo) Handler.Watch(service, target, methodInfo); } + /// + /// 在回调区间内暂时性的静态化服务实例 + /// + /// 回调区间 + /// 服务映射 + public static void Flash(Action callback, params KeyValuePair[] services) + { + Handler.Flash(callback, services); + } + /// /// 类型转为服务名 /// @@ -684,57 +634,111 @@ public static string Type2Service(Type type) { return Handler.Type2Service(type); } + #endregion + #region Container Extend API /// - /// 解除服务绑定 + /// 获取服务的绑定数据,如果绑定不存在则返回null /// - /// 解除绑定的服务 - public static void Unbind() + /// 服务名 + /// 服务绑定数据或者null + public static IBindData GetBind() { - Handler.Unbind(); + return Handler.GetBind(); } /// - /// 以单例的形式绑定一个服务 + /// 是否已经绑定了服务 /// - /// 服务名 - /// 服务实现 + /// 服务名 + /// 代表服务是否被绑定 + public static bool HasBind() + { + return Handler.HasBind(); + } + + /// + /// 是否可以生成服务 + /// + /// 服务名 + /// 服务是否可以被构建 + public static bool CanMake() + { + return Handler.CanMake(); + } + + /// + /// 服务是否是静态化的,如果服务不存在也将返回false + /// + /// 服务名 + /// 服务是否是静态化的 + public static bool IsStatic() + { + return Handler.IsStatic(); + } + + /// + /// 是否是别名 + /// + /// 服务名 + /// 是否是别名 + public static bool IsAlias() + { + return Handler.IsAlias(); + } + + /// + /// 常规绑定一个服务 + /// + /// 服务名,同时也是服务实现 /// 服务绑定数据 - public static IBindData Singleton(string service, Func concrete) + public static IBindData Bind() { - return Handler.Singleton(service, concrete); + return Handler.Bind(); } /// - /// 以单例的形式绑定一个服务 + /// 常规绑定一个服务 /// /// 服务名 /// 服务别名 /// 服务绑定数据 - public static IBindData Singleton() + public static IBindData Bind() { - return Handler.Singleton(); + return Handler.Bind(); } /// - /// 以单例的形式绑定一个服务 + /// 常规绑定一个服务 /// - /// 服务名,同时也是服务实现 + /// 服务名 + /// 服务实现 /// 服务绑定数据 - public static IBindData Singleton() + public static IBindData Bind(Func concrete) { - return Handler.Singleton(); + return Handler.Bind(concrete); } /// - /// 以单例的形式绑定一个服务 + /// 常规绑定一个服务 /// /// 服务名 /// 服务实现 /// 服务绑定数据 - public static IBindData Singleton(Func concrete) + public static IBindData Bind(Func concrete) { - return Handler.Singleton(concrete); + return Handler.Bind(concrete); + } + + /// + /// 常规绑定一个服务 + /// + /// 服务名 + /// 服务实现 + /// 服务绑定数据 + public static IBindData Bind(string service, Func concrete) + { + return Handler.Bind(service, concrete); } /// @@ -744,9 +748,9 @@ public static IBindData Singleton(Func c /// 服务别名 /// 如果绑定失败则返回历史绑定对象 /// 是否完成绑定 - public static bool SingletonIf(out IBindData bindData) + public static bool BindIf(out IBindData bindData) { - return Handler.SingletonIf(out bindData); + return Handler.BindIf(out bindData); } /// @@ -755,9 +759,9 @@ public static bool SingletonIf(out IBindData bindData) /// 服务名,同时也是服务实现 /// 如果绑定失败则返回历史绑定对象 /// 是否完成绑定 - public static bool SingletonIf(out IBindData bindData) + public static bool BindIf(out IBindData bindData) { - return Handler.SingletonIf(out bindData); + return Handler.BindIf(out bindData); } /// @@ -767,9 +771,21 @@ public static bool SingletonIf(out IBindData bindData) /// 服务实现 /// 如果绑定失败则返回历史绑定对象 /// 是否完成绑定 - public static bool SingletonIf(Func concrete, out IBindData bindData) + public static bool BindIf(Func concrete, out IBindData bindData) { - return Handler.SingletonIf(concrete, out bindData); + return Handler.BindIf(concrete, out bindData); + } + + /// + /// 如果服务不存在那么则绑定服务 + /// + /// 服务名 + /// 服务实现 + /// 如果绑定失败则返回历史绑定对象 + /// 是否完成绑定 + public static bool BindIf(Func concrete, out IBindData bindData) + { + return Handler.BindIf(concrete, out bindData); } /// @@ -779,52 +795,63 @@ public static bool SingletonIf(Func conc /// 服务实现 /// 如果绑定失败则返回历史绑定对象 /// 是否完成绑定 - public static bool SingletonIf(string service, Func concrete, out IBindData bindData) + public static bool BindIf(string service, Func concrete, out IBindData bindData) { - return Handler.SingletonIf(service, concrete, out bindData); + return Handler.BindIf(service, concrete, out bindData); } /// - /// 常规绑定一个服务 + /// 以单例的形式绑定一个服务 /// /// 服务名 /// 服务别名 /// 服务绑定数据 - public static IBindData Bind() + public static IBindData Singleton() { - return Handler.Bind(); + return Handler.Singleton(); } /// - /// 常规绑定一个服务 + /// 以单例的形式绑定一个服务 /// /// 服务名,同时也是服务实现 /// 服务绑定数据 - public static IBindData Bind() + public static IBindData Singleton() { - return Handler.Bind(); + return Handler.Singleton(); } /// - /// 常规绑定一个服务 + /// 以单例的形式绑定一个服务 /// /// 服务名 /// 服务实现 /// 服务绑定数据 - public static IBindData Bind(Func concrete) + public static IBindData Singleton(Func concrete) { - return Handler.Bind(concrete); + return Handler.Singleton(concrete); } /// - /// 常规绑定一个服务 + /// 以单例的形式绑定一个服务 + /// + /// 服务名 + /// 服务实现 + /// 服务绑定数据 + public static IBindData Singleton(Func concrete) + { + return Handler.Singleton(concrete); + } + + /// + /// 以单例的形式绑定一个服务 /// /// 服务名 /// 服务实现 /// 服务绑定数据 - public static IBindData Bind(string service, Func concrete) + public static IBindData Singleton(string service, Func concrete) { - return Handler.Bind(service, concrete); + return Handler.Singleton(service, concrete); } /// @@ -834,9 +861,9 @@ public static IBindData Bind(string service, Func /// 服务别名 /// 如果绑定失败则返回历史绑定对象 /// 是否完成绑定 - public static bool BindIf(out IBindData bindData) + public static bool SingletonIf(out IBindData bindData) { - return Handler.BindIf(out bindData); + return Handler.SingletonIf(out bindData); } /// @@ -845,9 +872,9 @@ public static bool BindIf(out IBindData bindData) /// 服务名,同时也是服务实现 /// 如果绑定失败则返回历史绑定对象 /// 是否完成绑定 - public static bool BindIf(out IBindData bindData) + public static bool SingletonIf(out IBindData bindData) { - return Handler.BindIf(out bindData); + return Handler.SingletonIf(out bindData); } /// @@ -857,33 +884,33 @@ public static bool BindIf(out IBindData bindData) /// 服务实现 /// 如果绑定失败则返回历史绑定对象 /// 是否完成绑定 - public static bool BindIf(Func concrete, out IBindData bindData) + public static bool SingletonIf(Func concrete, out IBindData bindData) { - return Handler.BindIf(concrete, out bindData); + return Handler.SingletonIf(concrete, out bindData); } /// /// 如果服务不存在那么则绑定服务 /// - /// 服务名 + /// 服务名 /// 服务实现 /// 如果绑定失败则返回历史绑定对象 /// 是否完成绑定 - public static bool BindIf(string service, Func concrete, out IBindData bindData) + public static bool SingletonIf(Func concrete, out IBindData bindData) { - return Handler.BindIf(service, concrete, out bindData); + return Handler.SingletonIf(concrete, out bindData); } /// - /// 绑定一个方法到容器 + /// 如果服务不存在那么则绑定服务 /// - /// 方法名 - /// 调用目标 - /// 调用方法 - public static IMethodBind BindMethod(string method, object target, - string call = null) + /// 服务名 + /// 服务实现 + /// 如果绑定失败则返回历史绑定对象 + /// 是否完成绑定 + public static bool SingletonIf(string service, Func concrete, out IBindData bindData) { - return Handler.BindMethod(method, target, call); + return Handler.SingletonIf(service, concrete, out bindData); } /// @@ -892,8 +919,8 @@ public static IMethodBind BindMethod(string method, object target, /// 方法名 /// 调用目标 /// 调用方法 - /// 方法绑定数据 - public static IMethodBind BindMethod(string method, object target, MethodInfo call) + public static IMethodBind BindMethod(string method, object target, + string call = null) { return Handler.BindMethod(method, target, call); } @@ -949,26 +976,123 @@ public static IMethodBind BindMethod(string method, Func - /// 解除绑定的方法 + /// 解除服务绑定 /// - /// - /// 解除目标 - /// 如果为字符串则作为调用方法名 - /// 如果为IMethodBind则作为指定方法 - /// 如果为其他对象则作为调用目标做全体解除 - /// - public static void UnbindMethod(object target) + /// 解除绑定的服务 + public static void Unbind() { - Handler.UnbindMethod(target); + Handler.Unbind(); } /// - /// 解除绑定服务 + /// 静态化一个服务,实例值会经过解决修饰器 /// - /// 服务名或者别名 - public static void Unbind(string service) + /// 服务名 + /// 实例值 + public static void Instance(object instance) { - Handler.Unbind(service); + Handler.Instance(instance); + } + + /// + /// 释放服务 + /// + /// 服务名 + public static void Release() + { + Handler.Release(); + } + + /// + /// 以依赖注入形式调用一个方法 + /// + /// 方法对象 + /// 方法名 + /// 用户传入的参数 + /// 方法返回值 + public static object Call(object instance, string method, params object[] userParams) + { + return Handler.Call(instance, method, userParams); + } + + /// + /// 以依赖注入的形式调用一个方法 + /// + /// 方法 + public static void Call(Action method) + { + Handler.Call(method); + } + + /// + /// 以依赖注入的形式调用一个方法 + /// + /// 方法 + public static void Call(Action method) + { + Handler.Call(method); + } + + /// + /// 以依赖注入的形式调用一个方法 + /// + /// 方法 + public static void Call(Action method) + { + Handler.Call(method); + } + + /// + /// 以依赖注入的形式调用一个方法 + /// + /// 方法 + public static void Call(Action method) + { + Handler.Call(method); + } + + /// + /// 包装一个依赖注入形式调用的一个方法 + /// + /// 方法 + /// 用户传入的参数 + /// 包装方法 + public static Action Wrap(Action method, params object[] userParams) + { + return Handler.Wrap(method, userParams); + } + + /// + /// 包装一个依赖注入形式调用的一个方法 + /// + /// 方法 + /// 用户传入的参数 + /// 包装方法 + public static Action Wrap(Action method, params object[] userParams) + { + return Handler.Wrap(method, userParams); + } + + /// + /// 包装一个依赖注入形式调用的一个方法 + /// + /// 方法 + /// 用户传入的参数 + /// 包装方法 + public static Action Wrap(Action method, params object[] userParams) + { + return Handler.Wrap(method, userParams); + } + + /// + /// 包装一个依赖注入形式调用的一个方法 + /// + /// 方法 + /// 用户传入的参数 + /// 包装方法 + public static Action Wrap(Action method, params object[] userParams) + { + return Handler.Wrap(method, userParams); } /// @@ -983,22 +1107,25 @@ public static TService Make(params object[] userParams) } /// - /// 释放服务 + /// 获取一个回调,当执行回调可以生成指定的服务 /// /// 服务名 - public static void Release() + /// 回调方案 + public static Func Factory() { - Handler.Release(); + return Handler.Factory(); } /// - /// 静态化一个服务,实例值会经过解决修饰器 + /// 关注指定的服务,当服务触发重定义时调用指定对象的指定方法 + /// 调用是以依赖注入的形式进行的 /// - /// 服务名 - /// 实例值 - public static void Instance(object instance) + /// 关注的服务名 + /// 当服务发生重定义时调用的目标 + /// 方法名 + public static void Watch(string service, object target, string method) { - Handler.Instance(instance); + Handler.Watch(service, target, method); } /// @@ -1013,13 +1140,14 @@ public static void Flash(Action callback, string service, object instance) } /// - /// 在回调区间内暂时性的静态化服务实例 + /// 类型转为服务名 /// - /// 回调区间 - /// 服务映射 - public static void Flash(Action callback, params KeyValuePair[] serviceMapping) + /// 服务类型 + /// 服务名 + public static string Type2Service() { - Handler.Flash(callback, serviceMapping); + return Handler.Type2Service(); } + #endregion } } \ No newline at end of file diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 2ce512b..fe39c86 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -763,12 +763,12 @@ internal void Unbind(IBindable bindable) /// 在回调区间内暂时性的静态化服务实例 /// /// 回调区间 - /// 服务映射 - public void Flash(Action callback, params KeyValuePair[] serviceMapping) + /// 服务映射 + public void Flash(Action callback, params KeyValuePair[] services) { lock (syncRoot) { - foreach (var service in serviceMapping) + foreach (var service in services) { if (HasInstance(service.Key)) { @@ -781,7 +781,7 @@ public void Flash(Action callback, params KeyValuePair[] service } } - Arr.Flash(serviceMapping, + Arr.Flash(services, service => Instance(service.Key, service.Value), service => Release(service.Key), callback); @@ -1198,7 +1198,7 @@ protected virtual object GetCompactInjectUserParams(ParameterInfo baseParam, ref var result = userParams; userParams = null; - if (baseParam.ParameterType == typeof(object) + if (baseParam.ParameterType == typeof(object) && result != null && result.Length == 1) { return result[0]; diff --git a/src/CatLib.Core/Support/Container/ContainerExtend.cs b/src/CatLib.Core/Support/Container/ContainerExtend.cs index 2d27955..bfd62ed 100644 --- a/src/CatLib.Core/Support/Container/ContainerExtend.cs +++ b/src/CatLib.Core/Support/Container/ContainerExtend.cs @@ -20,197 +20,120 @@ namespace CatLib public static class ContainerExtend { /// - /// 以依赖注入的形式调用一个方法 - /// - /// 服务容器 - /// 方法 - public static void Call(this IContainer container, Action method) - { - Guard.Requires(method != null); - container.Call(method.Target, method.Method); - } - - /// - /// 以依赖注入的形式调用一个方法 - /// - /// 服务容器 - /// 方法 - public static void Call(this IContainer container, Action method) - { - Guard.Requires(method != null); - container.Call(method.Target, method.Method); - } - - /// - /// 以依赖注入的形式调用一个方法 - /// - /// 服务容器 - /// 方法 - public static void Call(this IContainer container, Action method) - { - Guard.Requires(method != null); - container.Call(method.Target, method.Method); - } - - /// - /// 以依赖注入的形式调用一个方法 + /// 获取服务的绑定数据,如果绑定不存在则返回null /// + /// 服务名 /// 服务容器 - /// 方法 - public static void Call(this IContainer container, Action method) + /// 服务绑定数据或者null + public static IBindData GetBind(this IContainer container) { - Guard.Requires(method != null); - container.Call(method.Target, method.Method); + return container.GetBind(container.Type2Service(typeof(TService))); } /// - /// 包装一个依赖注入形式调用的一个方法 - /// - /// 服务容器 - /// 方法 - /// 用户传入的参数 - /// 包装方法 - public static Action Wrap(this IContainer container, Action method, params object[] userParams) - { - return () => - { - if (method != null) - { - container.Call(method.Target, method.Method, userParams); - } - }; - } - - /// - /// 包装一个依赖注入形式调用的一个方法 + /// 是否已经绑定了服务 /// + /// 服务名 /// 服务容器 - /// 方法 - /// 用户传入的参数 - /// 包装方法 - public static Action Wrap(this IContainer container, Action method, params object[] userParams) + /// 代表服务是否被绑定 + public static bool HasBind(this IContainer container) { - return () => - { - if (method != null) - { - container.Call(method.Target, method.Method, userParams); - } - }; + return container.HasBind(container.Type2Service(typeof(TService))); } /// - /// 包装一个依赖注入形式调用的一个方法 + /// 是否可以生成服务 /// + /// 服务名 /// 服务容器 - /// 方法 - /// 用户传入的参数 - /// 包装方法 - public static Action Wrap(this IContainer container, Action method, params object[] userParams) + /// 服务是否可以被构建 + public static bool CanMake(this IContainer container) { - return () => - { - if (method != null) - { - container.Call(method.Target, method.Method, userParams); - } - }; + return container.CanMake(container.Type2Service(typeof(TService))); } /// - /// 包装一个依赖注入形式调用的一个方法 + /// 服务是否是静态化的,如果服务不存在也将返回false /// + /// 服务名 /// 服务容器 - /// 方法 - /// 用户传入的参数 - /// 包装方法 - public static Action Wrap(this IContainer container, Action method, params object[] userParams) + /// 服务是否是静态化的 + public static bool IsStatic(this IContainer container) { - return () => - { - if (method != null) - { - container.Call(method.Target, method.Method, userParams); - } - }; + return container.IsStatic(container.Type2Service(typeof(TService))); } /// - /// 以依赖注入形式调用一个方法 + /// 是否是别名 /// + /// 服务名 /// 服务容器 - /// 方法对象 - /// 方法名 - /// 用户传入的参数 - /// 方法返回值 - /// ,null或者空字符串 - public static object Call(this IContainer container, object target, string method, params object[] userParams) + /// 是否是别名 + public static bool IsAlias(this IContainer container) { - Guard.Requires(target != null); - Guard.NotEmptyOrNull(method, "method"); - - var methodInfo = target.GetType().GetMethod(method); - return container.Call(target, methodInfo, userParams); + return container.IsAlias(container.Type2Service(typeof(TService))); } /// - /// 以单例的形式绑定一个服务 + /// 常规绑定一个服务 /// + /// 服务名,同时也是服务实现 /// 服务容器 - /// 服务名 - /// 服务实现 /// 服务绑定数据 - public static IBindData Singleton(this IContainer container, string service, - Func concrete) + public static IBindData Bind(this IContainer container) { - return container.Bind(service, concrete, true); + return container.Bind(container.Type2Service(typeof(TService)), typeof(TService), false); } /// - /// 解除服务绑定 + /// 常规绑定一个服务 /// - /// 解除绑定的服务 + /// 服务名 + /// 服务别名 /// 服务容器 - public static void Unbind(this IContainer container) + /// 服务绑定数据 + public static IBindData Bind(this IContainer container) { - container.Unbind(container.Type2Service(typeof(T))); + return container.Bind(container.Type2Service(typeof(TService)), typeof(TService), false) + .Alias(container.Type2Service(typeof(TAlias))); } /// - /// 以单例的形式绑定一个服务 + /// 常规绑定一个服务 /// /// 服务名 - /// 服务别名 /// 服务容器 + /// 服务实现 /// 服务绑定数据 - public static IBindData Singleton(this IContainer container) + public static IBindData Bind(this IContainer container, Func concrete) { - return container.Bind(container.Type2Service(typeof(TService)), typeof(TService), true) - .Alias(container.Type2Service(typeof(TAlias))); + Guard.Requires(concrete != null); + return container.Bind(container.Type2Service(typeof(TService)), concrete, false); } /// - /// 以单例的形式绑定一个服务 + /// 常规绑定一个服务 /// - /// 服务名,同时也是服务实现 + /// 服务名 /// 服务容器 + /// 服务实现 /// 服务绑定数据 - public static IBindData Singleton(this IContainer container) + public static IBindData Bind(this IContainer container, Func concrete) { - return container.Bind(container.Type2Service(typeof(TService)), typeof(TService), true); + return container.Bind(container.Type2Service(typeof(TService)), (c, p) => concrete.Invoke(), false); } /// - /// 以单例的形式绑定一个服务 + /// 常规绑定一个服务 /// - /// 服务名 /// 服务容器 + /// 服务名 /// 服务实现 /// 服务绑定数据 - public static IBindData Singleton(this IContainer container, + public static IBindData Bind(this IContainer container, string service, Func concrete) { - return container.Bind(container.Type2Service(typeof(TService)), concrete, true); + return container.Bind(service, concrete, false); } /// @@ -221,9 +144,9 @@ public static IBindData Singleton(this IContainer container, /// 服务容器 /// 如果绑定失败则返回历史绑定对象 /// 是否完成绑定 - public static bool SingletonIf(this IContainer container, out IBindData bindData) + public static bool BindIf(this IContainer container, out IBindData bindData) { - if (container.BindIf(container.Type2Service(typeof(TService)), typeof(TService), true, out bindData)) + if (container.BindIf(container.Type2Service(typeof(TService)), typeof(TService), false, out bindData)) { bindData.Alias(container.Type2Service(typeof(TAlias))); return true; @@ -238,9 +161,9 @@ public static bool SingletonIf(this IContainer container, out /// 服务容器 /// 如果绑定失败则返回历史绑定对象 /// 是否完成绑定 - public static bool SingletonIf(this IContainer container, out IBindData bindData) + public static bool BindIf(this IContainer container, out IBindData bindData) { - return container.BindIf(container.Type2Service(typeof(TService)), typeof(TService), true, out bindData); + return container.BindIf(container.Type2Service(typeof(TService)), typeof(TService), false, out bindData); } /// @@ -251,9 +174,24 @@ public static bool SingletonIf(this IContainer container, out IBindDat /// 服务实现 /// 如果绑定失败则返回历史绑定对象 /// 是否完成绑定 - public static bool SingletonIf(this IContainer container, Func concrete, out IBindData bindData) + public static bool BindIf(this IContainer container, Func concrete, out IBindData bindData) { - return container.BindIf(container.Type2Service(typeof(TService)), concrete, true, out bindData); + return container.BindIf(container.Type2Service(typeof(TService)), concrete, false, out bindData); + } + + /// + /// 如果服务不存在那么则绑定服务 + /// + /// 服务名 + /// 服务容器 + /// 服务实现 + /// 如果绑定失败则返回历史绑定对象 + /// 是否完成绑定 + public static bool BindIf(this IContainer container, Func concrete, out IBindData bindData) + { + Guard.Requires(concrete != null); + return container.BindIf(container.Type2Service(typeof(TService)), (c, p) => concrete.Invoke(), false, + out bindData); } /// @@ -264,59 +202,74 @@ public static bool SingletonIf(this IContainer container, Func服务实现 /// 如果绑定失败则返回历史绑定对象 /// 是否完成绑定 - public static bool SingletonIf(this IContainer container, string service, + public static bool BindIf(this IContainer container, string service, Func concrete, out IBindData bindData) { - return container.BindIf(service, concrete, true, out bindData); + return container.BindIf(service, concrete, false, out bindData); } /// - /// 常规绑定一个服务 + /// 以单例的形式绑定一个服务 + /// + /// 服务容器 + /// 服务名 + /// 服务实现 + /// 服务绑定数据 + public static IBindData Singleton(this IContainer container, string service, + Func concrete) + { + return container.Bind(service, concrete, true); + } + + /// + /// 以单例的形式绑定一个服务 /// /// 服务名 /// 服务别名 /// 服务容器 /// 服务绑定数据 - public static IBindData Bind(this IContainer container) + public static IBindData Singleton(this IContainer container) { - return container.Bind(container.Type2Service(typeof(TService)), typeof(TService), false) + return container.Bind(container.Type2Service(typeof(TService)), typeof(TService), true) .Alias(container.Type2Service(typeof(TAlias))); } /// - /// 常规绑定一个服务 + /// 以单例的形式绑定一个服务 /// /// 服务名,同时也是服务实现 /// 服务容器 /// 服务绑定数据 - public static IBindData Bind(this IContainer container) + public static IBindData Singleton(this IContainer container) { - return container.Bind(container.Type2Service(typeof(TService)), typeof(TService), false); + return container.Bind(container.Type2Service(typeof(TService)), typeof(TService), true); } /// - /// 常规绑定一个服务 + /// 以单例的形式绑定一个服务 /// /// 服务名 /// 服务容器 /// 服务实现 /// 服务绑定数据 - public static IBindData Bind(this IContainer container, Func concrete) + public static IBindData Singleton(this IContainer container, + Func concrete) { - return container.Bind(container.Type2Service(typeof(TService)), concrete, false); + return container.Bind(container.Type2Service(typeof(TService)), concrete, true); } /// - /// 常规绑定一个服务 + /// 以单例的形式绑定一个服务 /// + /// 服务名 /// 服务容器 - /// 服务名 /// 服务实现 /// 服务绑定数据 - public static IBindData Bind(this IContainer container, string service, - Func concrete) + public static IBindData Singleton(this IContainer container, + Func concrete) { - return container.Bind(service, concrete, false); + Guard.Requires(concrete != null); + return container.Bind(container.Type2Service(typeof(TService)), (c, p) => concrete.Invoke(), true); } /// @@ -327,9 +280,9 @@ public static IBindData Bind(this IContainer container, string service, /// 服务容器 /// 如果绑定失败则返回历史绑定对象 /// 是否完成绑定 - public static bool BindIf(this IContainer container, out IBindData bindData) + public static bool SingletonIf(this IContainer container, out IBindData bindData) { - if (container.BindIf(container.Type2Service(typeof(TService)), typeof(TService), false, out bindData)) + if (container.BindIf(container.Type2Service(typeof(TService)), typeof(TService), true, out bindData)) { bindData.Alias(container.Type2Service(typeof(TAlias))); return true; @@ -344,9 +297,9 @@ public static bool BindIf(this IContainer container, out IBind /// 服务容器 /// 如果绑定失败则返回历史绑定对象 /// 是否完成绑定 - public static bool BindIf(this IContainer container, out IBindData bindData) + public static bool SingletonIf(this IContainer container, out IBindData bindData) { - return container.BindIf(container.Type2Service(typeof(TService)), typeof(TService), false, out bindData); + return container.BindIf(container.Type2Service(typeof(TService)), typeof(TService), true, out bindData); } /// @@ -357,9 +310,24 @@ public static bool BindIf(this IContainer container, out IBindData bin /// 服务实现 /// 如果绑定失败则返回历史绑定对象 /// 是否完成绑定 - public static bool BindIf(this IContainer container, Func concrete, out IBindData bindData) + public static bool SingletonIf(this IContainer container, Func concrete, out IBindData bindData) { - return container.BindIf(container.Type2Service(typeof(TService)), concrete, false, out bindData); + return container.BindIf(container.Type2Service(typeof(TService)), concrete, true, out bindData); + } + + /// + /// 如果服务不存在那么则绑定服务 + /// + /// 服务名 + /// 服务容器 + /// 服务实现 + /// 如果绑定失败则返回历史绑定对象 + /// 是否完成绑定 + public static bool SingletonIf(this IContainer container, Func concrete, out IBindData bindData) + { + Guard.Requires(concrete != null); + return container.BindIf(container.Type2Service(typeof(TService)), (c, p) => concrete.Invoke(), true, + out bindData); } /// @@ -370,10 +338,10 @@ public static bool BindIf(this IContainer container, Func服务实现 /// 如果绑定失败则返回历史绑定对象 /// 是否完成绑定 - public static bool BindIf(this IContainer container, string service, + public static bool SingletonIf(this IContainer container, string service, Func concrete, out IBindData bindData) { - return container.BindIf(service, concrete, false, out bindData); + return container.BindIf(service, concrete, true, out bindData); } /// @@ -457,59 +425,191 @@ public static IMethodBind BindMethod(this IContainer container, } /// - /// 为服务设定一个别名 + /// 解除服务绑定 /// - /// 服务名 + /// 解除绑定的服务 /// 服务容器 - /// 别名 - /// 服务容器 - public static IContainer Alias(this IContainer container, string alias) + public static void Unbind(this IContainer container) { - return container.Alias(alias, container.Type2Service(typeof(TService))); + container.Unbind(container.Type2Service(typeof(TService))); } /// - /// 构造一个服务 + /// 静态化一个服务,实例值会经过解决修饰器 /// /// 服务名 /// 服务容器 - /// 用户提供的参数 - /// 服务实例 - public static TService Make(this IContainer container, params object[] userParams) + /// 实例值 + public static object Instance(this IContainer container, object instance) { - return (TService)container.Make(container.Type2Service(typeof(TService)), userParams); + return container.Instance(container.Type2Service(typeof(TService)), instance); } /// - /// 获取一个回调,当执行回调可以生成指定的服务 + /// 释放服务 /// /// 服务名 /// 服务容器 - /// 回调方案 - public static Func Factory(this IContainer container) + public static void Release(this IContainer container) { - return () => (TService)container.Factory(container.Type2Service(typeof(TService))).Invoke(); + container.Release(container.Type2Service(typeof(TService))); } /// - /// 释放服务 + /// 以依赖注入的形式调用一个方法 + /// + /// 服务容器 + /// 方法 + public static void Call(this IContainer container, Action method) + { + Guard.Requires(method != null); + container.Call(method.Target, method.Method); + } + + /// + /// 以依赖注入的形式调用一个方法 + /// + /// 服务容器 + /// 方法 + public static void Call(this IContainer container, Action method) + { + Guard.Requires(method != null); + container.Call(method.Target, method.Method); + } + + /// + /// 以依赖注入的形式调用一个方法 + /// + /// 服务容器 + /// 方法 + public static void Call(this IContainer container, Action method) + { + Guard.Requires(method != null); + container.Call(method.Target, method.Method); + } + + /// + /// 以依赖注入的形式调用一个方法 + /// + /// 服务容器 + /// 方法 + public static void Call(this IContainer container, Action method) + { + Guard.Requires(method != null); + container.Call(method.Target, method.Method); + } + + /// + /// 以依赖注入形式调用一个方法 + /// + /// 服务容器 + /// 方法对象 + /// 方法名 + /// 用户传入的参数 + /// 方法返回值 + /// ,null或者空字符串 + public static object Call(this IContainer container, object target, string method, params object[] userParams) + { + Guard.Requires(target != null); + Guard.NotEmptyOrNull(method, "method"); + + var methodInfo = target.GetType().GetMethod(method); + return container.Call(target, methodInfo, userParams); + } + + /// + /// 包装一个依赖注入形式调用的一个方法 + /// + /// 服务容器 + /// 方法 + /// 用户传入的参数 + /// 包装方法 + public static Action Wrap(this IContainer container, Action method, params object[] userParams) + { + return () => + { + if (method != null) + { + container.Call(method.Target, method.Method, userParams); + } + }; + } + + /// + /// 包装一个依赖注入形式调用的一个方法 + /// + /// 服务容器 + /// 方法 + /// 用户传入的参数 + /// 包装方法 + public static Action Wrap(this IContainer container, Action method, params object[] userParams) + { + return () => + { + if (method != null) + { + container.Call(method.Target, method.Method, userParams); + } + }; + } + + /// + /// 包装一个依赖注入形式调用的一个方法 + /// + /// 服务容器 + /// 方法 + /// 用户传入的参数 + /// 包装方法 + public static Action Wrap(this IContainer container, Action method, params object[] userParams) + { + return () => + { + if (method != null) + { + container.Call(method.Target, method.Method, userParams); + } + }; + } + + /// + /// 包装一个依赖注入形式调用的一个方法 + /// + /// 服务容器 + /// 方法 + /// 用户传入的参数 + /// 包装方法 + public static Action Wrap(this IContainer container, Action method, params object[] userParams) + { + return () => + { + if (method != null) + { + container.Call(method.Target, method.Method, userParams); + } + }; + } + + /// + /// 构造一个服务 /// /// 服务名 /// 服务容器 - public static void Release(this IContainer container) + /// 用户提供的参数 + /// 服务实例 + public static TService Make(this IContainer container, params object[] userParams) { - container.Release(container.Type2Service(typeof(TService))); + return (TService)container.Make(container.Type2Service(typeof(TService)), userParams); } /// - /// 静态化一个服务,实例值会经过解决修饰器 + /// 获取一个回调,当执行回调可以生成指定的服务 /// /// 服务名 /// 服务容器 - /// 实例值 - public static object Instance(this IContainer container, object instance) + /// 回调方案 + public static Func Factory(this IContainer container) { - return container.Instance(container.Type2Service(typeof(TService)), instance); + return () => (TService)container.Factory(container.Type2Service(typeof(TService))).Invoke(); } /// @@ -540,5 +640,16 @@ public static void Flash(this IContainer container, Action callback, string serv { container.Flash(callback, new KeyValuePair(service, instance)); } + + /// + /// 类型转为服务名 + /// + /// 服务类型 + /// 服务容器 + /// 服务名 + public static string Type2Service(this IContainer container) + { + return container.Type2Service(typeof(TService)); + } } } \ No newline at end of file diff --git a/src/CatLib.Core/Support/Container/IContainer.cs b/src/CatLib.Core/Support/Container/IContainer.cs index 3c77430..6ac4cc1 100644 --- a/src/CatLib.Core/Support/Container/IContainer.cs +++ b/src/CatLib.Core/Support/Container/IContainer.cs @@ -59,19 +59,19 @@ public interface IContainer /// 绑定一个服务 /// /// 服务名 - /// 服务实体 + /// 服务实现 /// 服务是否静态化 /// 服务绑定数据 - IBindData Bind(string service, Func concrete, bool isStatic); + IBindData Bind(string service, Type concrete, bool isStatic); /// /// 绑定一个服务 /// /// 服务名 - /// 服务实现 + /// 服务实体 /// 服务是否静态化 /// 服务绑定数据 - IBindData Bind(string service, Type concrete, bool isStatic); + IBindData Bind(string service, Func concrete, bool isStatic); /// /// 如果服务不存在那么则绑定服务 @@ -241,8 +241,8 @@ public interface IContainer /// 在回调区间内暂时性的静态化服务实例 /// /// 回调区间 - /// 服务映射 - void Flash(Action callback, params KeyValuePair[] serviceMapping); + /// 服务映射 + void Flash(Action callback, params KeyValuePair[] services); /// /// 类型转为服务名 From fab447dd2bbc2d12e142e9801a403da84ba00b24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Wed, 20 Dec 2017 16:04:38 +0800 Subject: [PATCH 67/91] container update --- .../Support/Container/Container.cs | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index aea2415..b71ed56 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -916,7 +916,20 @@ protected virtual object ResolveAttrPrimitive(Bindable makeServiceBindData, stri /// 解决结果 protected virtual object ResloveAttrClass(Bindable makeServiceBindData, string service, PropertyInfo baseParam) { - return Make(makeServiceBindData.GetContextual(service)); + try + { + return Make(makeServiceBindData.GetContextual(service)); + } + catch (Exception) + { + var result = SpeculationServiceByParamName(makeServiceBindData, baseParam.Name, baseParam.PropertyType); + if (result != null) + { + return result; + } + + throw; + } } /// @@ -963,10 +976,17 @@ protected virtual object ResloveClass(Bindable makeServiceBindData, string servi } catch (UnresolvableException) { + var result = SpeculationServiceByParamName(makeServiceBindData, baseParam.Name, baseParam.ParameterType); + if (result != null) + { + return result; + } + if (baseParam.IsOptional) { return baseParam.DefaultValue; } + throw; } } From 59b545c76df858c9edc9661ef24d15446352b461 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Thu, 28 Dec 2017 21:38:43 +0800 Subject: [PATCH 68/91] container add param name inject --- .../CatLib.Core.NetStandard.csproj | 1 + .../Support/Container/ContainerTests.cs | 111 +++++++++++++ src/CatLib.Core/CatLib.Core.csproj | 1 + .../Support/Container/Container.cs | 149 +++++++++++++----- src/CatLib.Core/Support/Container/Params.cs | 93 +++++++++++ src/CatLib.Core/Support/Util/Arr.cs | 33 ++++ src/CatLib.Core/Support/Util/Dict.cs | 15 +- 7 files changed, 359 insertions(+), 44 deletions(-) create mode 100644 src/CatLib.Core/Support/Container/Params.cs diff --git a/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj b/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj index 3a684e2..ac6284a 100644 --- a/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj +++ b/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj @@ -78,6 +78,7 @@ + diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs index 92264d1..6e43892 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs @@ -643,6 +643,17 @@ public void TestContainerCallWithNullParams() Assert.AreEqual(777, result); } + [TestMethod] + public void TestContainerCallWithErrorParams() + { + var container = MakeContainer(); + container.Instance("@num", "helloworld"); + ExceptionAssert.Throws(() => + { + container.Call(this, "TestContainerCall", null); + }); + } + /// /// 测试无效的传入参数 /// @@ -1706,6 +1717,106 @@ public void TestConstructorExceptionFunction() Assert.AreEqual(true, isException); } + private class ParamsTypeInjectTest + { + public int num1; + public long num2; + public string str; + + public ParamsTypeInjectTest(int num1, long num2,string str) + { + this.num1 = num1; + this.num2 = num2; + this.str = str; + } + } + + [TestMethod] + public void TestParamsUserParams() + { + var container = MakeContainer(); + container.Bind(); + + var result = container.Make(new Params + { + {"num2", 100}, + {"num1", 50}, + {"str", "helloworld"}, + }, 100, 200, "dog"); + + Assert.AreEqual(50, result.num1); + Assert.AreEqual(100, result.num2); + Assert.AreEqual("helloworld", result.str); + } + + [TestMethod] + public void TestMultParamsUserParams() + { + var container = MakeContainer(); + container.Bind(); + + var result = container.Make(new Params + { + {"num2", 100}, + {"num1", 50}, + }, 100, new Params + { + {"num2", 500}, + {"num1", 4000}, + {"str", "helloworld"}, + }, 200, "dog"); + + Assert.AreEqual(50, result.num1); + Assert.AreEqual(100, result.num2); + Assert.AreEqual("helloworld", result.str); + } + + [TestMethod] + public void TestParamsUserParamsThrowError() + { + var container = MakeContainer(); + container.Bind(); + + ExceptionAssert.Throws(() => + { + var result = container.Make(new Params + { + {"num2", 100}, + {"num1", "helloworld"}, + {"str", "helloworld"}, + }); + }); + } + + private class ContainerReplaceThrow : Container + { + // 测试由于开发者写错代码导致的bug是否被正确抛出异常 + protected override Func GetParamsMatcher(ref object[] userParams) + { + return (param) => + { + return 200; + }; + } + } + + [TestMethod] + public void TestReplaceContainerParamsUserParamsThrowError() + { + var container = new ContainerReplaceThrow(); + container.Bind(); + + ExceptionAssert.Throws(() => + { + container.Make(new Params + { + {"num2", 100}, + {"num1", "helloworld"}, + {"str", "helloworld"}, + }); + }); + } + /// /// 测试基础容器调用 /// diff --git a/src/CatLib.Core/CatLib.Core.csproj b/src/CatLib.Core/CatLib.Core.csproj index cb46ede..840623c 100644 --- a/src/CatLib.Core/CatLib.Core.csproj +++ b/src/CatLib.Core/CatLib.Core.csproj @@ -50,6 +50,7 @@ + diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index c0568a5..29f7c9e 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -806,16 +806,11 @@ protected virtual object GetDependenciesFromUserParams(ParameterInfo baseParam, for (var n = 0; n < userParams.Length; n++) { var userParam = userParams[n]; - if (baseParam.ParameterType.IsInstanceOfType(userParam)) - { - return Arr.RemoveAt(ref userParams, n); - } - object result; - if (ChangeType(userParam, baseParam.ParameterType, out result)) + if (ChangeType(ref userParam, baseParam.ParameterType)) { Arr.RemoveAt(ref userParams, n); - return result; + return userParam; } } @@ -825,17 +820,21 @@ protected virtual object GetDependenciesFromUserParams(ParameterInfo baseParam, /// /// 转换参数类型 /// - /// 参数 + /// 需要转换的参数 /// 转换到的类型 - /// 转换后的结果 /// 是否转换成功 - protected virtual bool ChangeType(object param, Type conversionType, out object result) + protected virtual bool ChangeType(ref object result, Type conversionType) { try { - if (conversionType.IsPrimitive && param is IConvertible) + if (conversionType.IsInstanceOfType(result)) + { + return true; + } + + if (conversionType.IsPrimitive && result is IConvertible) { - result = Convert.ChangeType(param, conversionType); + result = Convert.ChangeType(result, conversionType); return true; } } @@ -845,7 +844,6 @@ protected virtual bool ChangeType(object param, Type conversionType, out object // when throw exception then stop inject } - result = null; return false; } @@ -988,8 +986,7 @@ protected virtual object SpeculationServiceByParamName(Bindable makeServiceBindD } var instance = Make(service); - ChangeType(instance, paramType, out instance); - return instance; + return ChangeType(ref instance, paramType) ? instance : null; } /// @@ -1198,7 +1195,7 @@ protected virtual object GetCompactInjectUserParams(ParameterInfo baseParam, ref var result = userParams; userParams = null; - if (baseParam.ParameterType == typeof(object) + if (baseParam.ParameterType == typeof(object) && result != null && result.Length == 1) { return result[0]; @@ -1207,6 +1204,24 @@ protected virtual object GetCompactInjectUserParams(ParameterInfo baseParam, ref return result; } + /// + /// 获取参数()匹配器 + /// 开发者重写后可以实现自己的匹配器 + /// 如果调用获取到的匹配器后返回结果为null则表示没有匹配到参数 + /// + /// 用户传入的参数 + /// 匹配器,如果返回null则表示没有匹配器 + protected virtual Func GetParamsMatcher(ref object[] userParams) + { + if (userParams == null || userParams.Length <= 0) + { + return null; + } + + var tables = GetParamsTypeInUserParams(ref userParams); + return tables.Length <= 0 ? null : MakeParamsMatcher(tables); + } + /// /// 获取依赖解决结果 /// @@ -1219,41 +1234,54 @@ protected virtual object[] GetDependencies(Bindable makeServiceBindData, Paramet { var results = new List(baseParams.Length); + // 获取一个参数匹配器用于筛选参数 + var matcher = GetParamsMatcher(ref userParams); + foreach (var baseParam in baseParams) { + // 使用参数匹配器对参数进行匹配,参数匹配器是最先进行的,因为他们的匹配精度是最准确的 + var param = (matcher == null) ? null : matcher(baseParam); + // 当容器发现开发者使用 object 或者 object[] 作为参数类型时 // 我们尝试将所有用户传入的用户参数紧缩注入 - var param = GetCompactInjectUserParams(baseParam, ref userParams); - if (param != null) - { - results.Add(param); - continue; - } + param = param ?? GetCompactInjectUserParams(baseParam, ref userParams); // 从用户传入的参数中挑选合适的参数,按照相对顺序依次注入 - param = GetDependenciesFromUserParams(baseParam, ref userParams); - if (param != null) - { - results.Add(param); - continue; - } + param = param ?? GetDependenciesFromUserParams(baseParam, ref userParams); - // 尝试通过依赖注入容器来生成所需求的参数 - var needService = GetParamNeedsService(baseParam); + string needService = null; - if (baseParam.ParameterType.IsClass - || baseParam.ParameterType.IsInterface) + if (param == null) { - param = ResloveClass(makeServiceBindData, needService, baseParam); - } - else - { - param = ResolvePrimitive(makeServiceBindData, needService, baseParam); + // 尝试通过依赖注入容器来生成所需求的参数 + needService = GetParamNeedsService(baseParam); + + if (baseParam.ParameterType.IsClass + || baseParam.ParameterType.IsInterface) + { + param = ResloveClass(makeServiceBindData, needService, baseParam); + } + else + { + param = ResolvePrimitive(makeServiceBindData, needService, baseParam); + } } + // 对筛选到的参数进行注入检查 if (!CanInject(baseParam.ParameterType, param)) { - throw new UnresolvableException("[" + makeServiceBindData.Service + "] Params inject type must be [" + baseParam.ParameterType + "] , But instance is [" + param.GetType() + "] Make service is [" + needService + "]."); + var error = "[" + makeServiceBindData.Service + "] Params inject type must be [" + + baseParam.ParameterType + "] , But instance is [" + param.GetType() + "]"; + if (needService == null) + { + error += " Inject params from user incoming parameters."; + } + else + { + error += " Make service is [" + needService + "]."; + } + + throw new UnresolvableException(error); } results.Add(param); @@ -1516,5 +1544,50 @@ private BindData GetBindFillable(string service) BindData bindData; return binds.TryGetValue(service, out bindData) ? bindData : MakeEmptyBindData(service); } + + /// + /// 从中获取类型的变量 + /// + /// 用户传入参数 + /// 获取到的参数 + private Params[] GetParamsTypeInUserParams(ref object[] userParams) + { + var elements = Arr.Remove(ref userParams, value => value is Params); + var results = new Params[elements.Length]; + for (var i = 0; i < elements.Length; i++) + { + results[i] = (Params)elements[i]; + } + return results; + } + + /// + /// 生成一个默认的参数匹配器 + /// + /// 参数表 + /// 匹配器 + private Func MakeParamsMatcher(Params[] tables) + { + // 默认匹配器策略将会将参数名和参数表的参数名进行匹配 + // 最先匹配到的有效参数值将作为返回值返回 + return (parameterInfo) => + { + foreach (var table in tables) + { + object result; + if (!table.TryGetValue(parameterInfo.Name, out result)) + { + continue; + } + + if (ChangeType(ref result, parameterInfo.ParameterType)) + { + return result; + } + } + + return null; + }; + } } } \ No newline at end of file diff --git a/src/CatLib.Core/Support/Container/Params.cs b/src/CatLib.Core/Support/Container/Params.cs new file mode 100644 index 0000000..f182d79 --- /dev/null +++ b/src/CatLib.Core/Support/Container/Params.cs @@ -0,0 +1,93 @@ +/* + * 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.Collections.Generic; + +namespace CatLib +{ + /// + /// 参数名注入表 + /// + [ExcludeFromCodeCoverage] + public sealed class Params : IEnumerable> + { + /// + /// 参数表 + /// + private readonly Dictionary table = new Dictionary(); + + /// + /// 迭代器 + /// + /// 迭代器 + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return table.GetEnumerator(); + } + + /// + /// + /// + /// + IEnumerator> IEnumerable>.GetEnumerator() + { + return table.GetEnumerator(); + } + + /// + /// 获取或者设定一个参数 + /// + /// 参数名 + /// 参数值 + public object this[string key] + { + get + { + return table[key]; + } + set + { + table[key] = value; + } + } + + /// + /// 增加一个参数 + /// + /// 参数名 + /// 参数值 + public void Add(string key, object value) + { + table.Add(key, value); + } + + /// + /// 移除参数 + /// + /// 参数名 + /// + public bool Remove(string key) + { + return table.Remove(key); + } + + /// + /// 获取一个参数 + /// + /// 参数名 + /// 参数值 + /// 是否成功获取 + public bool TryGetValue(string key, out object value) + { + return table.TryGetValue(key, out value); + } + } +} diff --git a/src/CatLib.Core/Support/Util/Arr.cs b/src/CatLib.Core/Support/Util/Arr.cs index 2250835..11f1d93 100644 --- a/src/CatLib.Core/Support/Util/Arr.cs +++ b/src/CatLib.Core/Support/Util/Arr.cs @@ -10,6 +10,7 @@ */ using System; +using System.Collections.Generic; namespace CatLib { @@ -229,6 +230,38 @@ public static T[] Fill(int start, int length, T value, T[] source = null) return requested; } + /// + /// 将数组每个值传给回调函数,如果回调函数返回 true,则移除数组中对应的元素,并返回被移除的元素 + /// + /// 数组类型 + /// 规定数组 + /// 回调函数 + /// 被移除的数组 + public static T[] Remove(ref T[] source, Predicate predicate) + { + Guard.Requires(source != null); + Guard.Requires(predicate != null); + + if (source.Length <= 0) + { + return new T[] { }; + } + + var results = new List(); + + for (var i = source.Length - 1; i >= 0; i--) + { + if (!predicate.Invoke(source[i])) + { + continue; + } + results.Add(source[i]); + RemoveAt(ref source, i); + } + + return Reverse(results.ToArray()); + } + /// /// 输入数组中的每个值传给回调函数,如果回调函数返回 true,则把输入数组中的当前值加入结果数组中 /// diff --git a/src/CatLib.Core/Support/Util/Dict.cs b/src/CatLib.Core/Support/Util/Dict.cs index 82ca6ea..b08745b 100644 --- a/src/CatLib.Core/Support/Util/Dict.cs +++ b/src/CatLib.Core/Support/Util/Dict.cs @@ -46,30 +46,33 @@ public static IDictionary Filter(IDictionary - /// 将输入字典中的每个值传给回调函数,如果回调函数返回 true,则移除字典中对应的元素 + /// 将输入字典中的每个值传给回调函数,如果回调函数返回 true,则移除字典中对应的元素,并返回被移除的元素 /// /// 字典键类型 /// 字典值类型 /// 规定字典 /// 回调函数 - public static void Remove(IDictionary source, Func predicate) + /// 被移除的元素 + public static KeyValuePair[] Remove(IDictionary source, Func predicate) { Guard.Requires(source != null); Guard.Requires(predicate != null); - var list = new List(); + var results = new List>(); foreach (var result in source) { if (predicate.Invoke(result.Key, result.Value)) { - list.Add(result.Key); + results.Add(result); } } - foreach (var result in list) + foreach (var result in results) { - source.Remove(result); + source.Remove(result.Key); } + + return results.ToArray(); } /// From 91e34ccbfa8de4ebc06423de2ea267d37e8fdf7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Thu, 28 Dec 2017 21:42:53 +0800 Subject: [PATCH 69/91] assembly info update to 1.2 --- src/CatLib.Core.Tests/Properties/AssemblyInfo.cs | 4 ++-- src/CatLib.Core/Properties/AssemblyInfo.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/CatLib.Core.Tests/Properties/AssemblyInfo.cs b/src/CatLib.Core.Tests/Properties/AssemblyInfo.cs index 294fb01..3183efe 100644 --- a/src/CatLib.Core.Tests/Properties/AssemblyInfo.cs +++ b/src/CatLib.Core.Tests/Properties/AssemblyInfo.cs @@ -25,5 +25,5 @@ [assembly: Guid("3c9f4024-910c-4881-a04d-34a6c3a09019")] -[assembly: AssemblyVersion("1.1.4.0")] -[assembly: AssemblyFileVersion("1.1.4.0")] +[assembly: AssemblyVersion("1.2.0.0")] +[assembly: AssemblyFileVersion("1.2.0.0")] diff --git a/src/CatLib.Core/Properties/AssemblyInfo.cs b/src/CatLib.Core/Properties/AssemblyInfo.cs index 4efe5f8..047c619 100644 --- a/src/CatLib.Core/Properties/AssemblyInfo.cs +++ b/src/CatLib.Core/Properties/AssemblyInfo.cs @@ -26,8 +26,8 @@ [assembly: Guid("4204658e-81fd-4106-a347-890cd369c8a4")] -[assembly: AssemblyVersion("1.1.4.0")] -[assembly: AssemblyFileVersion("1.1.4.0")] +[assembly: AssemblyVersion("1.2.0.0")] +[assembly: AssemblyFileVersion("1.2.0.0")] [assembly: InternalsVisibleTo("Assembly-CSharp-Editor"), InternalsVisibleTo("Assembly-CSharp-Editor-firstpass"), From 81ea235c29b97167fd553ac91ef23f332d008d45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Fri, 29 Dec 2017 16:57:16 +0800 Subject: [PATCH 70/91] container optimization --- .../Support/Container/ContainerTests.cs | 37 +++++++++++++++++++ .../Support/Container/Container.cs | 4 +- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs index cb6b3e8..327c091 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs @@ -1817,6 +1817,43 @@ public void TestReplaceContainerParamsUserParamsThrowError() }); } + public class TestResloveAttrClassSpeculationService + { + [Inject] + public RuntimeException rex { get; set; } + + public UnresolvableException ex; + public TestResloveAttrClassSpeculationService(UnresolvableException ex) + { + this.ex = ex; + } + } + + [TestMethod] + public void TestResloveAttrClassSpeculationServiceFunc() + { + var container = new Container(); + container.Bind(); + container.Instance("@ex", new UnresolvableException()); + container.Instance("@rex", new UnresolvableException()); + var cls = container.Make(); + + Assert.AreSame(container.Make("@ex"), cls.ex); + } + + [TestMethod] + public void TestResloveAttrClassSpeculationServiceAttrs() + { + var container = new Container(); + container.Bind(); + container.Instance("@ex", new UnresolvableException()); + + ExceptionAssert.Throws(() => + { + container.Make(); + }); + } + /// /// 测试基础容器调用 /// diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index bea6802..606b3f7 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -271,7 +271,7 @@ public bool CanMake(string service) } var type = SpeculatedServiceType(service); - return !(type == null || type.IsPrimitive); + return !(type == null || type.IsPrimitive || type == typeof(string)); } } @@ -832,7 +832,7 @@ protected virtual bool ChangeType(ref object result, Type conversionType) return true; } - if (conversionType.IsPrimitive && result is IConvertible) + if (result is IConvertible) { result = Convert.ChangeType(result, conversionType); return true; From 72b61f16de38a0e2706fd8a20ac57c7b6c6ee59d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Fri, 29 Dec 2017 18:07:39 +0800 Subject: [PATCH 71/91] add variant type support --- .../CatLib.Core.NetStandard.csproj | 1 + .../Support/Container/ContainerTests.cs | 66 +++++++++++++++++++ src/CatLib.Core/CatLib.Core.csproj | 1 + .../Support/Container/Container.cs | 30 ++++++++- src/CatLib.Core/Support/Container/IVariant.cs | 21 ++++++ 5 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 src/CatLib.Core/Support/Container/IVariant.cs diff --git a/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj b/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj index ac6284a..460a801 100644 --- a/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj +++ b/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj @@ -76,6 +76,7 @@ + diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs index 327c091..0cdbe3d 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs @@ -1854,6 +1854,72 @@ public void TestResloveAttrClassSpeculationServiceAttrs() }); } + public class VariantModel : IVariant + { + public int num; + public VariantModel(int num) + { + this.num = num; + if (num == 0) + { + throw new Exception(); + } + } + } + + public class VariantFather + { + public long code; + public VariantModel model; + public VariantFather(long code, VariantModel model) + { + this.code = code; + this.model = model; + } + } + + /// + /// 测试类型变换 + /// + [TestMethod] + public void TestVariant() + { + var container = new Container(); + container.Bind(); + container.Bind(); + + var cls = container.Make(10, 20); + + Assert.AreEqual(10, cls.code); + Assert.AreEqual(20, cls.model.num); + } + + [TestMethod] + public void TestVariantThrowError() + { + var container = new Container(); + container.Bind(); + container.Bind(); + + ExceptionAssert.Throws(() => + { + container.Make(10, 0); + }); + } + + [TestMethod] + public void TestNullFromParams() + { + var container = new Container(); + container.Bind(); + container.Bind(); + + ExceptionAssert.Throws(() => + { + container.Make(10, new Params {{"model", null}}); + }); + } + /// /// 测试基础容器调用 /// diff --git a/src/CatLib.Core/CatLib.Core.csproj b/src/CatLib.Core/CatLib.Core.csproj index 840623c..65abff4 100644 --- a/src/CatLib.Core/CatLib.Core.csproj +++ b/src/CatLib.Core/CatLib.Core.csproj @@ -48,6 +48,7 @@ + diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 606b3f7..3d5802d 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -271,7 +271,7 @@ public bool CanMake(string service) } var type = SpeculatedServiceType(service); - return !(type == null || type.IsPrimitive || type == typeof(string)); + return !IsBasicType(type); } } @@ -788,6 +788,16 @@ public void Flash(Action callback, params KeyValuePair[] service } } + /// + /// 是否是依赖注入容器默认的基础类型 + /// + /// 基础类型 + /// 是否是基础类型 + protected virtual bool IsBasicType(Type type) + { + return type == null || type.IsPrimitive || type == typeof(string); + } + /// /// 从用户传入的参数中获取依赖 /// @@ -827,12 +837,26 @@ protected virtual bool ChangeType(ref object result, Type conversionType) { try { - if (conversionType.IsInstanceOfType(result)) + if (result == null || conversionType.IsInstanceOfType(result)) { return true; } - if (result is IConvertible) + if (IsBasicType(result.GetType()) && typeof(IVariant).IsAssignableFrom(conversionType)) + { + try + { + result = Make(Type2Service(conversionType), result); + return true; + } + catch (Exception) + { + // ignored + // when throw exception then stop inject + } + } + + if (result is IConvertible && typeof(IConvertible).IsAssignableFrom(conversionType)) { result = Convert.ChangeType(result, conversionType); return true; diff --git a/src/CatLib.Core/Support/Container/IVariant.cs b/src/CatLib.Core/Support/Container/IVariant.cs new file mode 100644 index 0000000..f3c1dde --- /dev/null +++ b/src/CatLib.Core/Support/Container/IVariant.cs @@ -0,0 +1,21 @@ +/* + * 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/ + */ + +namespace CatLib +{ + /// + /// 可转变的 + /// 实现该接口的类,允许依赖注入容器将用户传入的基本类型(包含string)转变为目标类 + /// + public interface IVariant + { + } +} From 17e1fd4fd213594b665d515a0230fcfd1b9ffc68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Tue, 9 Jan 2018 16:39:51 +0800 Subject: [PATCH 72/91] watch extend --- .../Support/Container/ContainerHelperTests.cs | 82 +++++++++++++++++++ src/CatLib.Core/CatLib/App.cs | 34 ++++++++ .../Support/Container/ContainerExtend.cs | 40 +++++++++ 3 files changed, 156 insertions(+) diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerHelperTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerHelperTests.cs index 6582b4a..3039c48 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerHelperTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerHelperTests.cs @@ -218,6 +218,88 @@ public void TestGetService() Assert.AreEqual(container.Type2Service(typeof(string)), container.Type2Service()); } + public class TestWatchCLass + { + public int value; + + public IContainer container; + + public void OnChange(int instance, IContainer container) + { + value = instance; + this.container = container; + } + } + + public interface IWatchTest + { + int getValue(); + } + + public class TestData : IWatchTest + { + private int val; + public TestData(int val) + { + this.val = val; + } + public int getValue() + { + return val; + } + } + + [TestMethod] + public void TestWatch() + { + var container = new Container(); + container.Instance(container); + + var cls = new TestWatchCLass(); + container.Watch(cls, "OnChange"); + container.Instance(100); + container.Instance(200); + + Assert.AreEqual(200, cls.value); + Assert.AreSame(container, cls.container); + } + + [TestMethod] + public void TestWatchLambda() + { + var container = new Container(); + container.Instance(container); + + var isCall = false; + container.Watch((val) => + { + isCall = true; + Assert.AreEqual(200, val.getValue()); + }); + container.Instance(new TestData(100)); + container.Instance(new TestData(200)); + + Assert.AreEqual(true, isCall); + Assert.AreEqual(true, isCall); + } + + [TestMethod] + public void TestWatchLambdaNoParam() + { + var container = new Container(); + container.Instance(container); + + var isCall = false; + container.Watch(() => + { + isCall = true; + }); + container.Instance(100); + container.Instance(200); + + Assert.AreEqual(true, isCall); + } + /// /// 生成容器 /// diff --git a/src/CatLib.Core/CatLib/App.cs b/src/CatLib.Core/CatLib/App.cs index d7b99e7..7017d8f 100644 --- a/src/CatLib.Core/CatLib/App.cs +++ b/src/CatLib.Core/CatLib/App.cs @@ -1128,6 +1128,40 @@ public static void Watch(string service, object target, string method) Handler.Watch(service, target, method); } + /// + /// 关注指定的服务,当服务触发重定义时调用指定对象的指定方法 + /// 调用是以依赖注入的形式进行的 + /// + /// 服务名 + /// 当服务发生重定义时调用的目标 + /// 方法名 + public static void Watch(object target, string method) + { + Handler.Watch(target, method); + } + + /// + /// 关注指定的服务,当服务触发重定义时调用指定对象的指定方法 + /// 调用是以依赖注入的形式进行的 + /// + /// 服务名 + /// 回调 + public static void Watch(Action method) + { + Handler.Watch(method); + } + + /// + /// 关注指定的服务,当服务触发重定义时调用指定对象的指定方法 + /// 调用是以依赖注入的形式进行的 + /// + /// 服务名 + /// 回调 + public static void Watch(Action method) + { + Handler.Watch(method); + } + /// /// 在回调区间内暂时性的静态化服务实例 /// diff --git a/src/CatLib.Core/Support/Container/ContainerExtend.cs b/src/CatLib.Core/Support/Container/ContainerExtend.cs index bfd62ed..5d87a36 100644 --- a/src/CatLib.Core/Support/Container/ContainerExtend.cs +++ b/src/CatLib.Core/Support/Container/ContainerExtend.cs @@ -629,6 +629,46 @@ public static void Watch(this IContainer container, string service, object targe container.Watch(service, target, methodInfo); } + /// + /// 关注指定的服务,当服务触发重定义时调用指定对象的指定方法 + /// 调用是以依赖注入的形式进行的 + /// + /// 服务名 + /// 服务容器 + /// 当服务发生重定义时调用的目标 + /// 方法名 + public static void Watch(this IContainer container, object target, string method) + { + Guard.Requires(method != null); + container.Watch(container.Type2Service(), target, method); + } + + /// + /// 关注指定的服务,当服务触发重定义时调用指定对象的指定方法 + /// 调用是以依赖注入的形式进行的 + /// + /// 服务名 + /// 服务容器 + /// 回调 + public static void Watch(this IContainer container, Action method) + { + Guard.Requires(method != null); + container.Watch(container.Type2Service(), method.Target, method.Method); + } + + /// + /// 关注指定的服务,当服务触发重定义时调用指定对象的指定方法 + /// 调用是以依赖注入的形式进行的 + /// + /// 服务名 + /// 服务容器 + /// 回调 + public static void Watch(this IContainer container, Action method) + { + Guard.Requires(method != null); + container.Watch(container.Type2Service(), method.Target, method.Method); + } + /// /// 在回调区间内暂时性的静态化服务实例 /// From a5520aedd7328cc305e65cc9335511343fbecdd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Tue, 9 Jan 2018 17:58:57 +0800 Subject: [PATCH 73/91] facade support watch sync --- src/CatLib.Core.Tests/CatLib/FacaedTests.cs | 101 ++++++++++++++++++-- src/CatLib.Core/CatLib/Facade.cs | 69 ++++++++++++- 2 files changed, 161 insertions(+), 9 deletions(-) diff --git a/src/CatLib.Core.Tests/CatLib/FacaedTests.cs b/src/CatLib.Core.Tests/CatLib/FacaedTests.cs index dc65e21..2ddbbd7 100644 --- a/src/CatLib.Core.Tests/CatLib/FacaedTests.cs +++ b/src/CatLib.Core.Tests/CatLib/FacaedTests.cs @@ -17,15 +17,90 @@ namespace CatLib.Tests [TestClass] public class FacaedTests { + public class FacaedTestClass : IFacaedTestClass + { + } - public class FacaedTestClass + public interface IFacaedTestClass + { + } + public class TestClassFacade : Facade { } - public class TestClassFacaed : Facade + public class TestClassFacadeError : Facade + { + + } + + [TestMethod] + public void FacadeErrorTest() { + var app = new Application(); + app.Bootstrap(); + app.Singleton(); + var isError = false; + try + { + var data = TestClassFacadeError.Instance; + } + catch (TypeInitializationException) + { + isError = true; + } + + Assert.AreEqual(true, isError); + } + + [TestMethod] + public void FacadeWatchTest() + { + var app = new Application(); + app.Bootstrap(); + app.Singleton().Alias(); + var old = TestClassFacade.Instance; + app.Unbind(); + app.Singleton().Alias(); + + Assert.AreNotSame(old, TestClassFacade.Instance); + } + + [TestMethod] + public void FacadeWatchTestWithInstance() + { + var app = new Application(); + app.Bootstrap(); + app.Singleton().Alias(); + + var cls = new FacaedTestClass(); + app.Instance(cls); + + Assert.AreSame(cls, TestClassFacade.Instance); + } + + [TestMethod] + public void FacadeMakeFaild() + { + var app = new Application(); + app.Bootstrap(); + app.Singleton().Alias(); + var old = TestClassFacade.Instance; + + Assert.AreNotEqual(null, old); + app.Unbind(); + + var isError = false; + try + { + var data = TestClassFacade.Instance; + } + catch (UnresolvableException) + { + isError = true; + } + Assert.AreEqual(true, isError); } /// @@ -36,15 +111,29 @@ public void FacadeTest() { var app = new Application(); app.Bootstrap(); - var obj = new FacaedTestClass(); + IFacaedTestClass obj = new FacaedTestClass(); app.Singleton((c, p) => { return obj; - }); + }).Alias(); - Assert.AreEqual(obj, TestClassFacaed.Instance); + Assert.AreSame(obj, TestClassFacade.Instance); //double run - Assert.AreEqual(obj, TestClassFacaed.Instance); + Assert.AreSame(obj, TestClassFacade.Instance); + Assert.AreSame(obj, TestClassFacade.Instance); + } + + [TestMethod] + public void FacadeReleaseTest() + { + var app = new Application(); + app.Bootstrap(); + app.Singleton().Alias(); + + var data = TestClassFacade.Instance; + Assert.AreSame(data, TestClassFacade.Instance); + app.Release(); + Assert.AreNotSame(data, TestClassFacade.Instance); } } } diff --git a/src/CatLib.Core/CatLib/Facade.cs b/src/CatLib.Core/CatLib/Facade.cs index c424403..1eb6b58 100644 --- a/src/CatLib.Core/CatLib/Facade.cs +++ b/src/CatLib.Core/CatLib/Facade.cs @@ -14,16 +14,79 @@ namespace CatLib /// /// 门面 /// - public abstract class Facade + public abstract class Facade { + /// + /// 实例 + /// + private static TService service; + + /// + /// 绑定数据 + /// + private static IBindable binder; + + /// + /// 是否已经被初始化 + /// + private static bool inited; + + /// + /// 门面静态构造 + /// + static Facade() + { + if (!typeof(TService).IsInterface) + { + throw new RuntimeException("Facade<" + typeof(TService).Name + "> , generic type must be interface."); + } + + App.OnNewApplication += app => + { + service = default(TService); + binder = null; + inited = false; + }; + } + /// /// 门面实例 /// - public static T Instance + public static TService Instance { get { - return App.Make(); + if (service != null) + { + return service; + } + + Init(); + return service = App.Make(); + } + } + + /// + /// 初始化 + /// + private static void Init() + { + if (!inited) + { + App.Watch((service) => Facade.service = service); + inited = true; + } + + var newBinder = App.GetBind(); + if (newBinder == null) + { + return; + } + + if (binder == null || binder != newBinder) + { + newBinder.OnRelease((_, __) => service = default(TService)); + binder = newBinder; } } } From 6837dcf8da4c2c2684b5549f69aef24ba59001b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Tue, 9 Jan 2018 18:37:18 +0800 Subject: [PATCH 74/91] container call function support static function --- .../Support/Container/MethodContainerTests.cs | 27 +++++++++++++++++ src/CatLib.Core/CatLib/Facade.cs | 29 ++++++++++++++---- .../Support/Container/Container.cs | 22 +++++++++----- .../Support/Container/MethodContainer.cs | 30 ++++++++++++++----- 4 files changed, 87 insertions(+), 21 deletions(-) diff --git a/src/CatLib.Core.Tests/Support/Container/MethodContainerTests.cs b/src/CatLib.Core.Tests/Support/Container/MethodContainerTests.cs index 42202ef..efe424f 100644 --- a/src/CatLib.Core.Tests/Support/Container/MethodContainerTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/MethodContainerTests.cs @@ -9,6 +9,7 @@ * Document: http://catlib.io/ */ +using System; using CatLib.Tests; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -80,6 +81,32 @@ public void TestBindExcistsMethod() }); } + public static object TestStaticMethodAction(int num) + { + return num; + } + + [TestMethod] + public void TestStaticMethod() + { + new Application(); + App.BindMethod("echo", TestStaticMethodAction); + Assert.AreEqual(200, App.Invoke("echo", 200)); + } + + [TestMethod] + public void TestUnbindStaticMethod() + { + new Application(); + var bind = App.BindMethod("echo", TestStaticMethodAction); + Assert.AreEqual(100, App.Invoke("echo", 100)); + App.UnbindMethod(bind); + ExceptionAssert.Throws(() => + { + App.Invoke("echo", 200); + }); + } + [TestMethod] public void TestUnbindWithObject() { diff --git a/src/CatLib.Core/CatLib/Facade.cs b/src/CatLib.Core/CatLib/Facade.cs index 1eb6b58..830fc7f 100644 --- a/src/CatLib.Core/CatLib/Facade.cs +++ b/src/CatLib.Core/CatLib/Facade.cs @@ -61,26 +61,25 @@ public static TService Instance return service; } - Init(); - return service = App.Make(); + return Make(); } } /// /// 初始化 /// - private static void Init() + private static TService Make() { if (!inited) { - App.Watch((service) => Facade.service = service); + App.Watch(ServiceRebound); inited = true; } var newBinder = App.GetBind(); - if (newBinder == null) + if (newBinder == null || !newBinder.IsStatic) { - return; + return App.Make(); } if (binder == null || binder != newBinder) @@ -88,6 +87,24 @@ private static void Init() newBinder.OnRelease((_, __) => service = default(TService)); binder = newBinder; } + + return service = App.Make(); + } + + /// + /// 当服务被重绑定时 + /// + /// 新的服务实例 + private static void ServiceRebound(TService service) + { + var newBinder = App.GetBind(); + if (newBinder == null || !newBinder.IsStatic) + { + Facade.service = default(TService); + return; + } + + Facade.service = service; } } } \ No newline at end of file diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 3d5802d..9376925 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -480,15 +480,17 @@ public object Invoke(string method, params object[] userParams) /// ,null public object Call(object target, MethodInfo methodInfo, params object[] userParams) { - Guard.NotNull(target, "instance"); - Guard.NotNull(methodInfo, "methodInfo"); - - var type = target.GetType(); + Guard.Requires(methodInfo != null); + if (!methodInfo.IsStatic) + { + Guard.Requires(target != null); + } + var parameter = methodInfo.GetParameters(); lock (syncRoot) { - var bindData = GetBindFillable(Type2Service(type)); + var bindData = GetBindFillable(target != null ? Type2Service(target.GetType()) : null); userParams = parameter.Length > 0 ? GetDependencies(bindData, parameter, userParams) : new object[] { }; return methodInfo.Invoke(target, userParams); } @@ -675,9 +677,13 @@ public IContainer OnRebound(string service, Action callback) /// 方法信息 public void Watch(string service, object target, MethodInfo methodInfo) { - Guard.Requires(target != null); Guard.Requires(methodInfo != null); + if (!methodInfo.IsStatic) + { + Guard.Requires(target != null); + } + OnRebound(service, (instance) => { Call(target, methodInfo, instance); @@ -1586,7 +1592,9 @@ private object CreateInstance(Bindable makeServiceBindData, Type makeServiceType private BindData GetBindFillable(string service) { BindData bindData; - return binds.TryGetValue(service, out bindData) ? bindData : MakeEmptyBindData(service); + return service != null && binds.TryGetValue(service, out bindData) + ? bindData + : MakeEmptyBindData(service); } /// diff --git a/src/CatLib.Core/Support/Container/MethodContainer.cs b/src/CatLib.Core/Support/Container/MethodContainer.cs index e9d8d4a..c55da15 100644 --- a/src/CatLib.Core/Support/Container/MethodContainer.cs +++ b/src/CatLib.Core/Support/Container/MethodContainer.cs @@ -64,13 +64,17 @@ internal MethodContainer(Container container, Func /// 通过这个名字可以调用方法 /// 方法调用目标 - /// 在方法调用目标中被调用的方法 + /// 在方法调用目标中被调用的方法 /// - public IMethodBind Bind(string method, object target, MethodInfo call) + public IMethodBind Bind(string method, object target, MethodInfo methodInfo) { Guard.NotEmptyOrNull(method, "method"); - Guard.Requires(target != null); - Guard.Requires(call != null); + Guard.Requires(methodInfo != null); + + if (!methodInfo.IsStatic) + { + Guard.Requires(target != null); + } lock (syncRoot) { @@ -79,17 +83,21 @@ public IMethodBind Bind(string method, object target, MethodInfo call) throw new RuntimeException("Method [" + method + "] is already bind"); } + var methodBind = new MethodBind(this, container, method, target, methodInfo); + methodMappings[method] = methodBind; + + if (target == null) + { + return methodBind; + } + List targetMappings; if (!targetToMethodsMappings.TryGetValue(target, out targetMappings)) { targetToMethodsMappings[target] = targetMappings = new List(); } - var methodBind = new MethodBind(this, container, method, target, call); - - methodMappings[method] = methodBind; targetMappings.Add(method); - return methodBind; } } @@ -166,6 +174,12 @@ internal void Unbind(MethodBind methodBind) lock (syncRoot) { methodMappings.Remove(methodBind.Service); + + if (methodBind.Target == null) + { + return; + } + List methods; if (!targetToMethodsMappings.TryGetValue(methodBind.Target, out methods)) { From d4f598c12a842ddb50f204e12dfab028d73fb94f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Tue, 9 Jan 2018 18:59:16 +0800 Subject: [PATCH 75/91] facade test update --- src/CatLib.Core.Tests/CatLib/FacaedTests.cs | 70 +++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/src/CatLib.Core.Tests/CatLib/FacaedTests.cs b/src/CatLib.Core.Tests/CatLib/FacaedTests.cs index 2ddbbd7..6302e92 100644 --- a/src/CatLib.Core.Tests/CatLib/FacaedTests.cs +++ b/src/CatLib.Core.Tests/CatLib/FacaedTests.cs @@ -135,5 +135,75 @@ public void FacadeReleaseTest() app.Release(); Assert.AreNotSame(data, TestClassFacade.Instance); } + + [TestMethod] + public void TestNotStaticBindFacade() + { + var app = new Application(); + app.Bootstrap(); + app.Bind().Alias(); + + var data = TestClassFacade.Instance; + Assert.AreNotSame(data, TestClassFacade.Instance); + Assert.AreNotSame(TestClassFacade.Instance, TestClassFacade.Instance); + } + + [TestMethod] + public void TestBindingStateSwitchSingletonToBind() + { + var app = new Application(); + app.Bootstrap(); + app.Singleton().Alias(); + + var data = TestClassFacade.Instance; + Assert.AreSame(data, TestClassFacade.Instance); + + app.Unbind(); + app.Bind().Alias(); + Assert.AreNotSame(data, TestClassFacade.Instance); + Assert.AreNotSame(TestClassFacade.Instance, TestClassFacade.Instance); + } + + [TestMethod] + public void TestBindingStateSwitchBindToSingleton() + { + var app = new Application(); + app.Bootstrap(); + app.Bind().Alias(); + + var data = TestClassFacade.Instance; + Assert.AreNotSame(data, TestClassFacade.Instance); + Assert.AreNotSame(TestClassFacade.Instance, TestClassFacade.Instance); + + app.Unbind(); + app.Singleton().Alias(); + data = TestClassFacade.Instance; + Assert.AreSame(data, TestClassFacade.Instance); + Assert.AreSame(TestClassFacade.Instance, TestClassFacade.Instance); + } + + [TestMethod] + public void TestNotBind() + { + var app = new Application(); + app.Bootstrap(); + app.Instance(new FacaedTestClass()); + + var data = TestClassFacade.Instance; + Assert.AreSame(data, TestClassFacade.Instance); + + app.Release(); + + var isError = false; + try + { + data = TestClassFacade.Instance; + } + catch (UnresolvableException) + { + isError = true; + } + Assert.AreEqual(true, isError); + } } } From eaf188ee9d55122fe41a31b060ae6757f31f998b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Wed, 10 Jan 2018 15:35:20 +0800 Subject: [PATCH 76/91] app support inherit --- src/CatLib.Core/CatLib/App.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CatLib.Core/CatLib/App.cs b/src/CatLib.Core/CatLib/App.cs index 7017d8f..4cd5cf6 100644 --- a/src/CatLib.Core/CatLib/App.cs +++ b/src/CatLib.Core/CatLib/App.cs @@ -19,7 +19,7 @@ namespace CatLib /// CatLib实例 /// [ExcludeFromCodeCoverage] - public static class App + public class App { #region Original /// From b342e742342babbc1f2d145c277a4b7d0b6262f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Wed, 10 Jan 2018 16:28:37 +0800 Subject: [PATCH 77/91] app update --- src/CatLib.Core/CatLib/App.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CatLib.Core/CatLib/App.cs b/src/CatLib.Core/CatLib/App.cs index 4cd5cf6..7017d8f 100644 --- a/src/CatLib.Core/CatLib/App.cs +++ b/src/CatLib.Core/CatLib/App.cs @@ -19,7 +19,7 @@ namespace CatLib /// CatLib实例 /// [ExcludeFromCodeCoverage] - public class App + public static class App { #region Original /// From 0e869337bd23b8119f26dcbc734266b3d016242a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Wed, 10 Jan 2018 16:36:07 +0800 Subject: [PATCH 78/91] app update --- src/CatLib.Core/CatLib/App.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CatLib.Core/CatLib/App.cs b/src/CatLib.Core/CatLib/App.cs index 7017d8f..4cd5cf6 100644 --- a/src/CatLib.Core/CatLib/App.cs +++ b/src/CatLib.Core/CatLib/App.cs @@ -19,7 +19,7 @@ namespace CatLib /// CatLib实例 /// [ExcludeFromCodeCoverage] - public static class App + public class App { #region Original /// From 8c8672ace31c0ee891897b2631d3aa09f44b162d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Thu, 11 Jan 2018 17:08:57 +0800 Subject: [PATCH 79/91] bug fixed --- .../Support/Container/ContainerHelperTests.cs | 8 ++++++ src/CatLib.Core/CatLib/App.cs | 11 ++++++++ .../Support/Container/Container.cs | 28 +++++++++++++------ .../Support/Container/ContainerExtend.cs | 15 ++++++++++ 4 files changed, 54 insertions(+), 8 deletions(-) diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerHelperTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerHelperTests.cs index 3039c48..a2901c1 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerHelperTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerHelperTests.cs @@ -39,6 +39,14 @@ public void MakeTService() Assert.AreSame(this, obj); } + [TestMethod] + public void MakeTypeService() + { + var container = MakeContainer(); + var obj = container.Make(typeof(ContainerHelperTests)); + Assert.AreSame(this, obj); + } + /// /// 以单例形式绑定 /// diff --git a/src/CatLib.Core/CatLib/App.cs b/src/CatLib.Core/CatLib/App.cs index 4cd5cf6..ce4a1c2 100644 --- a/src/CatLib.Core/CatLib/App.cs +++ b/src/CatLib.Core/CatLib/App.cs @@ -1106,6 +1106,17 @@ public static TService Make(params object[] userParams) return Handler.Make(userParams); } + /// + /// 构造一个服务 + /// + /// 服务类型 + /// 用户提供的参数 + /// 服务实例 + public static object Make(Type type, params object[] userParams) + { + return Handler.Make(type, userParams); + } + /// /// 获取一个回调,当执行回调可以生成指定的服务 /// diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 9376925..dfb0e80 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -293,6 +293,7 @@ public bool IsStatic(string service) /// 是否是别名 public bool IsAlias(string name) { + name = FormatService(name); return aliases.ContainsKey(name); } @@ -353,6 +354,11 @@ public IContainer Alias(string alias, string service) public bool BindIf(string service, Func concrete, bool isStatic, out IBindData bindData) { var bind = GetBind(service); + if (bind == null && (HasInstance(service) || IsAlias(service))) + { + bindData = null; + return false; + } bindData = bind ?? Bind(service, concrete, isStatic); return bind == null; } @@ -367,9 +373,7 @@ public bool BindIf(string service, Func concrete, /// 服务绑定数据 public bool BindIf(string service, Type concrete, bool isStatic, out IBindData bindData) { - var bind = GetBind(service); - bindData = bind ?? Bind(service, concrete, isStatic); - return bind == null; + return BindIf(service, WrapperTypeBuilder(service, concrete), isStatic, out bindData); } /// @@ -383,11 +387,7 @@ public bool BindIf(string service, Type concrete, bool isStatic, out IBindData b public IBindData Bind(string service, Type concrete, bool isStatic) { Guard.NotNull(concrete, "concrete"); - return Bind(service, (c, param) => - { - var container = (Container)c; - return container.CreateInstance(GetBindFillable(service), concrete, param); - }, isStatic); + return Bind(service, WrapperTypeBuilder(service, concrete), isStatic); } /// @@ -804,6 +804,18 @@ protected virtual bool IsBasicType(Type type) return type == null || type.IsPrimitive || type == typeof(string); } + /// + /// 包装一个类型,可以被用来生成服务 + /// + /// 服务名 + /// 类型 + /// 根据类型生成的服务 + protected virtual Func WrapperTypeBuilder(string service, Type concrete) + { + service = FormatService(service); + return (container, userParams) => ((Container)container).CreateInstance(GetBindFillable(service), concrete, userParams); + } + /// /// 从用户传入的参数中获取依赖 /// diff --git a/src/CatLib.Core/Support/Container/ContainerExtend.cs b/src/CatLib.Core/Support/Container/ContainerExtend.cs index 5d87a36..3c1d6f1 100644 --- a/src/CatLib.Core/Support/Container/ContainerExtend.cs +++ b/src/CatLib.Core/Support/Container/ContainerExtend.cs @@ -601,6 +601,21 @@ public static TService Make(this IContainer container, params object[] return (TService)container.Make(container.Type2Service(typeof(TService)), userParams); } + /// + /// 构造一个服务 + /// + /// 服务容器 + /// 服务类型 + /// 用户提供的参数 + /// 服务实例 + public static object Make(this IContainer container, Type type, params object[] userParams) + { + var service = container.Type2Service(type); + IBindData binder; + container.BindIf(service, type, false, out binder); + return container.Make(service, userParams); + } + /// /// 获取一个回调,当执行回调可以生成指定的服务 /// From 90429538d31619232adadcb133f93c14f6f0b5e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Thu, 11 Jan 2018 18:34:01 +0800 Subject: [PATCH 80/91] container optimization --- src/CatLib.Core/CatLib/App.cs | 4 ++-- src/CatLib.Core/Support/Container/Container.cs | 5 +++-- src/CatLib.Core/Support/Container/ContainerExtend.cs | 5 +++-- src/CatLib.Core/Support/Container/IContainer.cs | 3 ++- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/CatLib.Core/CatLib/App.cs b/src/CatLib.Core/CatLib/App.cs index ce4a1c2..f838698 100644 --- a/src/CatLib.Core/CatLib/App.cs +++ b/src/CatLib.Core/CatLib/App.cs @@ -1122,9 +1122,9 @@ public static object Make(Type type, params object[] userParams) /// /// 服务名 /// 回调方案 - public static Func Factory() + public static Func Factory(params object[] userParams) { - return Handler.Factory(); + return Handler.Factory(userParams); } /// diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index dfb0e80..d0ca364 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -523,10 +523,11 @@ public object this[string service] /// 获取一个回调,当执行回调可以生成指定的服务 /// /// 服务名或别名 + /// 用户传入的参数 /// 回调方案 - public Func Factory(string service) + public Func Factory(string service, params object[] userParams) { - return () => Make(service); + return () => Make(service, userParams); } /// diff --git a/src/CatLib.Core/Support/Container/ContainerExtend.cs b/src/CatLib.Core/Support/Container/ContainerExtend.cs index 3c1d6f1..5c117f8 100644 --- a/src/CatLib.Core/Support/Container/ContainerExtend.cs +++ b/src/CatLib.Core/Support/Container/ContainerExtend.cs @@ -621,10 +621,11 @@ public static object Make(this IContainer container, Type type, params object[] /// /// 服务名 /// 服务容器 + /// 用户传入的参数 /// 回调方案 - public static Func Factory(this IContainer container) + public static Func Factory(this IContainer container, params object[] userParams) { - return () => (TService)container.Factory(container.Type2Service(typeof(TService))).Invoke(); + return () => (TService)container.Make(container.Type2Service(typeof(TService)), userParams); } /// diff --git a/src/CatLib.Core/Support/Container/IContainer.cs b/src/CatLib.Core/Support/Container/IContainer.cs index 6ac4cc1..6f2e22d 100644 --- a/src/CatLib.Core/Support/Container/IContainer.cs +++ b/src/CatLib.Core/Support/Container/IContainer.cs @@ -187,8 +187,9 @@ public interface IContainer /// 获取一个回调,当执行回调可以生成指定的服务 /// /// 服务名或别名 + /// 用户传入的参数 /// 回调方案 - Func Factory(string service); + Func Factory(string service, params object[] userParams); /// /// 为服务设定一个别名 From 11e4d17b2c064822cb8cbd86864fc42085ce2b47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Fri, 12 Jan 2018 14:32:09 +0800 Subject: [PATCH 81/91] container optimization --- .../Support/Container/ContainerTests.cs | 27 ++++++++++++++++++- .../Support/Container/Container.cs | 27 ++++++++++++++----- 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs index 0cdbe3d..7ebcade 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs @@ -156,6 +156,29 @@ public void NullTagService() #endregion #region Bind + /// + /// 测试无法被绑定的类型 + /// + [TestMethod] + public void TestBindUnableBuilt() + { + var container = MakeContainer(); + + IBindData binder; + Assert.AreEqual(false, container.BindIf(out binder)); + + var isError = false; + try + { + container.Bind(); + } + catch (RuntimeException) + { + isError = true; + } + Assert.AreEqual(true, isError); + } + /// /// 是否能够进行如果不存在则绑定的操作 /// @@ -567,8 +590,10 @@ public void TestFactory() container.Instance(container); container.Instance("hello", 123); - var fac = container.Factory(); + var fac = container.Factory(123); Assert.AreEqual(container.Make(), fac.Invoke()); + var fac2 = container.Factory("hello", 333); + Assert.AreEqual(123, fac2.Invoke()); } [TestMethod] diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index d0ca364..8294ccd 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -271,7 +271,7 @@ public bool CanMake(string service) } var type = SpeculatedServiceType(service); - return !IsBasicType(type); + return !IsBasicType(type) && !IsUnableType(type); } } @@ -373,6 +373,11 @@ public bool BindIf(string service, Func concrete, /// 服务绑定数据 public bool BindIf(string service, Type concrete, bool isStatic, out IBindData bindData) { + if (IsUnableType(concrete)) + { + bindData = null; + return false; + } return BindIf(service, WrapperTypeBuilder(service, concrete), isStatic, out bindData); } @@ -387,6 +392,10 @@ public bool BindIf(string service, Type concrete, bool isStatic, out IBindData b public IBindData Bind(string service, Type concrete, bool isStatic) { Guard.NotNull(concrete, "concrete"); + if (IsUnableType(concrete)) + { + throw new RuntimeException("Bind type [" + concrete + "] can not built"); + } return Bind(service, WrapperTypeBuilder(service, concrete), isStatic); } @@ -805,6 +814,16 @@ protected virtual bool IsBasicType(Type type) return type == null || type.IsPrimitive || type == typeof(string); } + /// + /// 是否是无法被构建的类型 + /// + /// 类型 + /// 是否可以被构建 + protected virtual bool IsUnableType(Type type) + { + return type == null || type.IsAbstract || type.IsInterface || type.IsArray || type.IsEnum; + } + /// /// 包装一个类型,可以被用来生成服务 /// @@ -1576,11 +1595,7 @@ private object Build(BindData makeServiceBindData, object[] userParams) /// 服务实例 private object CreateInstance(Bindable makeServiceBindData, Type makeServiceType, object[] userParams) { - if (makeServiceType == null - || makeServiceType.IsAbstract - || makeServiceType.IsInterface - || makeServiceType.IsArray - || makeServiceType.IsEnum) + if (IsUnableType(makeServiceType)) { return null; } From b99c99a26adc50fc1d15b3d2ca3fbaf6369b8838 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Sat, 13 Jan 2018 14:04:38 +0800 Subject: [PATCH 82/91] container optimization --- .../CatLib.Core.Tests.csproj | 1 + .../Container/ContainerPerformanceTests.cs | 60 +++++++++++++++++++ .../Support/Container/Container.cs | 5 ++ 3 files changed, 66 insertions(+) create mode 100644 src/CatLib.Core.Tests/Support/Container/ContainerPerformanceTests.cs diff --git a/src/CatLib.Core.Tests/CatLib.Core.Tests.csproj b/src/CatLib.Core.Tests/CatLib.Core.Tests.csproj index 5c2881e..41c945f 100644 --- a/src/CatLib.Core.Tests/CatLib.Core.Tests.csproj +++ b/src/CatLib.Core.Tests/CatLib.Core.Tests.csproj @@ -36,6 +36,7 @@ + diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerPerformanceTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerPerformanceTests.cs new file mode 100644 index 0000000..08be288 --- /dev/null +++ b/src/CatLib.Core.Tests/Support/Container/ContainerPerformanceTests.cs @@ -0,0 +1,60 @@ +/* + * 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; +using System.Diagnostics; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace CatLib.Tests.Stl +{ + /// + /// 容器性能测试 + /// + [TestClass] + public class ContainerPerformanceTests + { + public void Watch(string name ,Action action, int count = 1) + { + var sw = new Stopwatch(); + sw.Start(); + while (count-- > 0) + { + action(); + } + sw.Stop(); + Console.WriteLine("["+ name + "]执行花费{0}ms.", sw.Elapsed.TotalMilliseconds); + } + + public class TestSerializeClass + { + + } + + [TestMethod] + public void TestCreateInstance() + { + Watch("CreateInstance()", () => + { + Activator.CreateInstance(typeof(TestSerializeClass)); + }, 1000000); + + Watch("CreateInstance(null)",() => + { + Activator.CreateInstance(typeof(TestSerializeClass), null); + }, 1000000); + + Watch("CreateInstance(object[])", () => + { + Activator.CreateInstance(typeof(TestSerializeClass), new object[]{}); + }, 1000000); + } + } +} diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 8294ccd..9679f27 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -1604,6 +1604,11 @@ private object CreateInstance(Bindable makeServiceBindData, Type makeServiceType try { + // 如果参数不存在那么在反射时不写入参数可以获得更好的性能 + if (userParams == null || userParams.Length <= 0) + { + return Activator.CreateInstance(makeServiceType); + } return Activator.CreateInstance(makeServiceType, userParams); } catch (Exception ex) From 47bb5cebaf24e0434e5e997b649c5a7cdbee0bd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Sat, 13 Jan 2018 14:55:36 +0800 Subject: [PATCH 83/91] container optimization --- .../Support/Container/Container.cs | 39 +++++++++---------- .../Support/Container/MethodContainer.cs | 6 +-- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 9679f27..e424fdc 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -69,7 +69,7 @@ public class Container : IContainer /// /// 已经被解决过的服务名 /// - private readonly Dictionary resolved; + private readonly HashSet resolved; /// /// 重定义事件 @@ -131,7 +131,7 @@ public Container(int prime = 64) binds = new Dictionary(prime * 4); resolving = new List>((int)(prime * 0.25)); release = new List>((int)(prime * 0.25)); - resolved = new Dictionary(prime * 4); + resolved = new HashSet(); findType = new SortSet, int>(); findTypeCache = new Dictionary(prime * 4); rebound = new Dictionary>>(prime); @@ -249,7 +249,7 @@ public bool IsResolved(string service) lock (syncRoot) { service = AliasToService(service); - return resolved.ContainsKey(service) || instances.ContainsKey(service); + return resolved.Contains(service) || instances.ContainsKey(service); } } @@ -494,13 +494,13 @@ public object Call(object target, MethodInfo methodInfo, params object[] userPar { Guard.Requires(target != null); } - + var parameter = methodInfo.GetParameters(); lock (syncRoot) { var bindData = GetBindFillable(target != null ? Type2Service(target.GetType()) : null); - userParams = parameter.Length > 0 ? GetDependencies(bindData, parameter, userParams) : new object[] { }; + userParams = GetDependencies(bindData, parameter, userParams) ?? new object[] { }; return methodInfo.Invoke(target, userParams); } } @@ -693,7 +693,7 @@ public void Watch(string service, object target, MethodInfo methodInfo) { Guard.Requires(target != null); } - + OnRebound(service, (instance) => { Call(target, methodInfo, instance); @@ -893,7 +893,7 @@ protected virtual bool ChangeType(ref object result, Type conversionType) // when throw exception then stop inject } } - + if (result is IConvertible && typeof(IConvertible).IsAssignableFrom(conversionType)) { result = Convert.ChangeType(result, conversionType); @@ -1258,7 +1258,7 @@ protected virtual bool CheckCompactInjectUserParams(ParameterInfo baseParam, obj } return baseParam.ParameterType == typeof(object[]) - || baseParam.ParameterType == typeof(object); + || baseParam.ParameterType == typeof(object); } /// @@ -1314,6 +1314,11 @@ protected virtual Func GetParamsMatcher(ref object[] user /// 生成的实例类型和需求类型不一致 protected virtual object[] GetDependencies(Bindable makeServiceBindData, ParameterInfo[] baseParams, object[] userParams) { + if (baseParams.Length <= 0) + { + return null; + } + var results = new List(baseParams.Length); // 获取一个参数匹配器用于筛选参数 @@ -1353,7 +1358,7 @@ protected virtual object[] GetDependencies(Bindable makeServiceBindData, Paramet if (!CanInject(baseParam.ParameterType, param)) { var error = "[" + makeServiceBindData.Service + "] Params inject type must be [" + - baseParam.ParameterType + "] , But instance is [" + param.GetType() + "]"; + baseParam.ParameterType + "] , But instance is [" + param.GetType() + "]"; if (needService == null) { error += " Inject params from user incoming parameters."; @@ -1390,15 +1395,9 @@ protected virtual object[] GetConstructorsInjectParams(Bindable makeServiceBindD Exception exception = null; foreach (var constructor in constructors) { - var parameter = constructor.GetParameters(); - if (parameter.Length <= 0) - { - return null; - } - try { - return GetDependencies(makeServiceBindData, parameter, userParams); + return GetDependencies(makeServiceBindData, constructor.GetParameters(), userParams); } catch (Exception ex) { @@ -1470,7 +1469,7 @@ private void TriggerOnRebound(string service) callback.Invoke(instance); } }, Pair(typeof(IBindData), bind), - Pair(typeof(BindData), bind)); + Pair(typeof(BindData), bind)); } /// @@ -1541,7 +1540,9 @@ private object Resolve(string service, params object[] userParams) try { var bindData = GetBindFillable(service); - return Inject(bindData, Build(bindData, userParams)); + var result = Inject(bindData, Build(bindData, userParams)); + resolved.Add(bindData.Service); + return result; } finally { @@ -1567,8 +1568,6 @@ private object Inject(BindData bindData, object instance) ? Instance(bindData.Service, instance) : TriggerOnResolving(bindData, bindData.TriggerResolving(instance)); - resolved[bindData.Service] = true; - return instance; } diff --git a/src/CatLib.Core/Support/Container/MethodContainer.cs b/src/CatLib.Core/Support/Container/MethodContainer.cs index c55da15..093a413 100644 --- a/src/CatLib.Core/Support/Container/MethodContainer.cs +++ b/src/CatLib.Core/Support/Container/MethodContainer.cs @@ -120,10 +120,8 @@ public object Invoke(string method, params object[] userParams) throw MakeMethodNotFoundException(method); } - var injectParams = methodBind.ParameterInfos.Length > 0 - ? dependenciesResolved(methodBind, methodBind.ParameterInfos, userParams) - : new object[] { }; - + var injectParams = dependenciesResolved(methodBind, methodBind.ParameterInfos, userParams) ?? + new object[] { }; return methodBind.MethodInfo.Invoke(methodBind.Target, injectParams); } } From 0bee29a3a17e77130cecbdae746527ccc6e6b327 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Mon, 15 Jan 2018 13:18:31 +0800 Subject: [PATCH 84/91] container support IDisposable --- .../Support/Container/ContainerTests.cs | 19 +++++++++++++++++++ src/CatLib.Core/CatLib/Facade.cs | 16 ++++++++-------- .../Support/Container/Container.cs | 14 ++++++++++++++ 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs index 7ebcade..6c8eb9b 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs @@ -1592,6 +1592,25 @@ public void CanInstanceWithRelease() } Assert.Fail(); } + + public class TestDisposableClass : IDisposable + { + public bool isDispose; + public void Dispose() + { + isDispose = true; + } + } + + [TestMethod] + public void TestDisposableRelease() + { + var container = MakeContainer(); + container.Singleton(); + var cls = container.Make(); + container.Release(); + Assert.AreEqual(true, cls.isDispose); + } #endregion [TestMethod] diff --git a/src/CatLib.Core/CatLib/Facade.cs b/src/CatLib.Core/CatLib/Facade.cs index 830fc7f..257c9d8 100644 --- a/src/CatLib.Core/CatLib/Facade.cs +++ b/src/CatLib.Core/CatLib/Facade.cs @@ -19,7 +19,7 @@ public abstract class Facade /// /// 实例 /// - private static TService service; + private static TService instance; /// /// 绑定数据 @@ -43,7 +43,7 @@ static Facade() App.OnNewApplication += app => { - service = default(TService); + instance = default(TService); binder = null; inited = false; }; @@ -56,9 +56,9 @@ public static TService Instance { get { - if (service != null) + if (instance != null) { - return service; + return instance; } return Make(); @@ -84,11 +84,11 @@ private static TService Make() if (binder == null || binder != newBinder) { - newBinder.OnRelease((_, __) => service = default(TService)); + newBinder.OnRelease((_, __) => instance = default(TService)); binder = newBinder; } - return service = App.Make(); + return instance = App.Make(); } /// @@ -100,11 +100,11 @@ private static void ServiceRebound(TService service) var newBinder = App.GetBind(); if (newBinder == null || !newBinder.IsStatic) { - Facade.service = default(TService); + instance = default(TService); return; } - Facade.service = service; + instance = service; } } } \ No newline at end of file diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index e424fdc..ebe44a1 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -604,6 +604,7 @@ public void Release(string service) var bindData = GetBindFillable(service); bindData.TriggerRelease(instance); TriggerOnRelease(bindData, instance); + DisposeInstance(instance); instances.Remove(service); } } @@ -1453,6 +1454,19 @@ private void TriggerOnRelease(IBindData bindData, object obj) } } + /// + /// 释放实例 + /// + /// 实例 + private void DisposeInstance(object obj) + { + var disposable = obj as IDisposable; + if (disposable != null) + { + disposable.Dispose(); + } + } + /// /// 触发服务重定义事件 /// From 6d8d208e42d691d3415b600aa44ebdd000cff8ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Tue, 16 Jan 2018 17:14:37 +0800 Subject: [PATCH 85/91] container extend perfect --- .../Support/Container/ContainerTests.cs | 21 +++++++++++++++++- src/CatLib.Core/CatLib/App.cs | 20 +++++++++++++++++ .../Support/Container/ContainerExtend.cs | 22 +++++++++++++++++++ .../Support/Container/IContainer.cs | 14 ++++++++++++ 4 files changed, 76 insertions(+), 1 deletion(-) diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs index 6c8eb9b..dd00994 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs @@ -737,7 +737,6 @@ public void TestLooseParameters() #endregion #region Make - public class MakeTestClass { private readonly MakeTestClassDependency dependency; @@ -2091,6 +2090,26 @@ public void TestFlashOnBind() }, App.Type2Service(typeof(IBindData)), 200); }); } + + [TestMethod] + public void TestHasInstance() + { + var container = new Application(); + container.Instance(container); + + Assert.AreEqual(true, container.HasInstance()); + Assert.AreEqual(false, container.HasInstance()); + } + + [TestMethod] + public void TestIsResolved() + { + var container = new Application(); + container.Instance(container); + + Assert.AreEqual(true, container.IsResolved()); + Assert.AreEqual(false, container.IsResolved()); + } #endregion /// diff --git a/src/CatLib.Core/CatLib/App.cs b/src/CatLib.Core/CatLib/App.cs index f838698..5f0b7f3 100644 --- a/src/CatLib.Core/CatLib/App.cs +++ b/src/CatLib.Core/CatLib/App.cs @@ -352,6 +352,26 @@ public static bool HasBind(string service) return Handler.HasBind(service); } + /// + /// 是否已经实例静态化 + /// + /// 服务名 + /// 是否已经静态化 + public static bool HasInstance() + { + return Handler.HasInstance(); + } + + /// + /// 服务是否已经被解决过 + /// + /// 服务名 + /// 是否已经被解决过 + public static bool IsResolved() + { + return Handler.IsResolved(); + } + /// /// 是否可以生成服务 /// diff --git a/src/CatLib.Core/Support/Container/ContainerExtend.cs b/src/CatLib.Core/Support/Container/ContainerExtend.cs index 5c117f8..e65639b 100644 --- a/src/CatLib.Core/Support/Container/ContainerExtend.cs +++ b/src/CatLib.Core/Support/Container/ContainerExtend.cs @@ -41,6 +41,28 @@ public static bool HasBind(this IContainer container) return container.HasBind(container.Type2Service(typeof(TService))); } + /// + /// 是否已经实例静态化 + /// + /// 服务名 + /// 服务容器 + /// 是否已经静态化 + public static bool HasInstance(this IContainer container) + { + return container.HasInstance(container.Type2Service()); + } + + /// + /// 服务是否已经被解决过 + /// + /// 服务名 + /// 服务容器 + /// 是否已经被解决过 + public static bool IsResolved(this IContainer container) + { + return container.IsResolved(container.Type2Service()); + } + /// /// 是否可以生成服务 /// diff --git a/src/CatLib.Core/Support/Container/IContainer.cs b/src/CatLib.Core/Support/Container/IContainer.cs index 6f2e22d..a7f8ef9 100644 --- a/src/CatLib.Core/Support/Container/IContainer.cs +++ b/src/CatLib.Core/Support/Container/IContainer.cs @@ -34,6 +34,20 @@ public interface IContainer /// 返回一个bool值代表服务是否被绑定 bool HasBind(string service); + /// + /// 是否已经实例静态化 + /// + /// 服务名或别名 + /// 是否已经静态化 + bool HasInstance(string service); + + /// + /// 服务是否已经被解决过 + /// + /// 服务名或别名 + /// 是否已经被解决过 + bool IsResolved(string service); + /// /// 是否可以生成服务 /// From 6d0d686fed9fda66f48bb9908996950bc760af37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Tue, 16 Jan 2018 18:16:19 +0800 Subject: [PATCH 86/91] add flush check --- .../Support/Container/ContainerTests.cs | 24 +++++++ .../Support/Container/Container.cs | 69 ++++++++++++++----- 2 files changed, 76 insertions(+), 17 deletions(-) diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs index dd00994..de791ba 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs @@ -2110,6 +2110,30 @@ public void TestIsResolved() Assert.AreEqual(true, container.IsResolved()); Assert.AreEqual(false, container.IsResolved()); } + + [TestMethod] + public void TestFlushAndInstance() + { + var container = new Application(); + container.Instance(container); + + container.OnRelease((_, __) => + { + container.Instance(container); + }); + + var isError = false; + try + { + container.Flush(); + } + catch (RuntimeException) + { + isError = true; + } + + Assert.AreEqual(true, isError); + } #endregion /// diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index ebe44a1..45e5a4a 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -117,6 +117,11 @@ protected Stack UserParamsStack get { return userParamsStack; } } + /// + /// 是否在清空过程中 + /// + private bool flushing; + /// /// 构造一个容器 /// @@ -140,6 +145,7 @@ public Container(int prime = 64) injectTarget = typeof(InjectAttribute); methodContainer = new MethodContainer(this, GetDependencies); + flushing = false; } /// @@ -158,6 +164,7 @@ public void Tag(string tag, params string[] service) lock (syncRoot) { + GuardFlushing(); List list; if (!tags.TryGetValue(tag, out list)) { @@ -320,6 +327,7 @@ public IContainer Alias(string alias, string service) lock (syncRoot) { + GuardFlushing(); if (aliases.ContainsKey(alias)) { throw new RuntimeException("Alias [" + alias + "] is already exists."); @@ -415,6 +423,8 @@ public IBindData Bind(string service, Func concret service = FormatService(service); lock (syncRoot) { + GuardFlushing(); + if (binds.ContainsKey(service)) { throw new RuntimeException("Bind [" + service + "] already exists."); @@ -451,6 +461,7 @@ public IBindData Bind(string service, Func concret /// 方法绑定数据 public IMethodBind BindMethod(string method, object target, MethodInfo call) { + GuardFlushing(); return methodContainer.Bind(method, target, call); } @@ -552,6 +563,7 @@ public object Instance(string service, object instance) Guard.NotEmptyOrNull(service, "service"); lock (syncRoot) { + GuardFlushing(); service = AliasToService(service); var bindData = GetBind(service); @@ -620,6 +632,7 @@ public IContainer OnFindType(Func finder, int priority = int.MaxVa Guard.NotNull(finder, "finder"); lock (syncRoot) { + GuardFlushing(); findType.Add(finder, priority); } return this; @@ -635,6 +648,7 @@ public IContainer OnRelease(Action callback) Guard.NotNull(callback, "callback"); lock (syncRoot) { + GuardFlushing(); release.Add(callback); } return this; @@ -650,6 +664,7 @@ public IContainer OnResolving(Func callback) Guard.NotNull(callback, "callback"); lock (syncRoot) { + GuardFlushing(); resolving.Add(callback); } return this; @@ -666,6 +681,7 @@ public IContainer OnRebound(string service, Action callback) Guard.NotNull(callback, "callback"); lock (syncRoot) { + GuardFlushing(); service = AliasToService(service); List> list; @@ -722,25 +738,33 @@ public virtual void Flush() { lock (syncRoot) { - foreach (var service in Dict.Keys(instances)) + try { - Release(service); - } + flushing = true; + foreach (var service in Dict.Keys(instances)) + { + Release(service); + } - tags.Clear(); - aliases.Clear(); - aliasesReverse.Clear(); - instances.Clear(); - binds.Clear(); - resolving.Clear(); - release.Clear(); - resolved.Clear(); - findType.Clear(); - findTypeCache.Clear(); - buildStack.Clear(); - userParamsStack.Clear(); - rebound.Clear(); - methodContainer.Flush(); + tags.Clear(); + aliases.Clear(); + aliasesReverse.Clear(); + instances.Clear(); + binds.Clear(); + resolving.Clear(); + release.Clear(); + resolved.Clear(); + findType.Clear(); + findTypeCache.Clear(); + buildStack.Clear(); + userParamsStack.Clear(); + rebound.Clear(); + methodContainer.Flush(); + } + finally + { + flushing = false; + } } } @@ -1413,6 +1437,17 @@ protected virtual object[] GetConstructorsInjectParams(Bindable makeServiceBindD throw exception; } + /// + /// 验证重置状态 + /// + private void GuardFlushing() + { + if (flushing) + { + throw new RuntimeException("Container is flushing can not "); + } + } + /// /// 获取别名最终对应的服务名 /// From 7c654dfc30bcd702e727ce3a898104cf6aac8748 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Wed, 17 Jan 2018 14:38:18 +0800 Subject: [PATCH 87/91] lru cache update --- src/CatLib.Core/Support/LruCache/LruCache.cs | 82 +++++++++++++------- 1 file changed, 56 insertions(+), 26 deletions(-) diff --git a/src/CatLib.Core/Support/LruCache/LruCache.cs b/src/CatLib.Core/Support/LruCache/LruCache.cs index ecc540f..bcd2382 100644 --- a/src/CatLib.Core/Support/LruCache/LruCache.cs +++ b/src/CatLib.Core/Support/LruCache/LruCache.cs @@ -27,11 +27,6 @@ public sealed class LruCache : ILruCache /// private readonly int maxCapacity; - /// - /// Lru Cache - /// - private readonly Dictionary> lruCache; - /// /// 头节点 /// @@ -90,6 +85,11 @@ IEnumerator IEnumerable.GetEnumerator() } } + /// + /// 元素计数 + /// + private int count; + /// /// 创建一个Lru缓存 /// @@ -97,7 +97,7 @@ public LruCache(int maxCapacity) { Guard.Requires(maxCapacity > 0); this.maxCapacity = maxCapacity; - lruCache = new Dictionary>(); + count = 0; } /// @@ -108,15 +108,19 @@ public LruCache(int maxCapacity) public void Add(TKey key, TVal value) { Guard.Requires(key != null); - CacheNode result; - if (lruCache.TryGetValue(key, out result)) + var result = header; + while (result != null) { - result.Replace(value); - MakeUsed(result); - return; + if (result.KeyValue.Key.Equals(key)) + { + result.Replace(value); + MakeUsed(result); + return; + } + result = result.Forward; } - if (lruCache.Count >= maxCapacity) + if (count >= maxCapacity) { RemoveLeastUsed(); } @@ -133,7 +137,7 @@ public void Add(TKey key, TVal value) MakeUsed(addedNode); } - lruCache.Add(key, addedNode); + count++; } /// @@ -143,24 +147,37 @@ public void Add(TKey key, TVal value) public void Remove(TKey key) { Guard.Requires(key != null); - CacheNode result; - if (!lruCache.TryGetValue(key, out result)) + var result = header; + while (result != null) + { + if (result.KeyValue.Key.Equals(key)) + { + break; + } + result = result.Forward; + } + + if (result == null) { return; } - lruCache.Remove(key); + if (result == tail) { tail = result.Backward; + tail.Forward = null; } - if (result == header) + else if (result == header) { header = result.Forward; + header.Backward = null; } - if (result.Backward != null) + else if (result.Backward != null) { result.Backward.Forward = result.Forward; + result.Forward.Backward = result.Backward; } + count--; } /// @@ -186,8 +203,17 @@ public void Remove(TKey key) public bool Get(TKey key, out TVal val, TVal defaultVal = default(TVal)) { Guard.Requires(key != null); - CacheNode result; - if (!lruCache.TryGetValue(key, out result)) + var result = header; + while (result != null) + { + if (result.KeyValue.Key.Equals(key)) + { + break; + } + result = result.Forward; + } + + if (result == null) { val = defaultVal; return false; @@ -203,7 +229,7 @@ public void Remove(TKey key) /// public int Count { - get { return lruCache.Count; } + get { return count; } } /// @@ -243,15 +269,11 @@ private void RemoveLeastUsed() if (OnRemoveLeastUsed != null) { OnRemoveLeastUsed.Invoke(tail.KeyValue.Key, tail.KeyValue.Value); - if (lruCache.Count < maxCapacity) - { - return; - } } - lruCache.Remove(tail.KeyValue.Key); tail.Backward.Forward = null; tail = tail.Backward; + count--; } /// @@ -260,6 +282,11 @@ private void RemoveLeastUsed() /// 节点 private void MakeUsed(CacheNode node) { + if (node == header) + { + return; + } + if (node.Forward == null && node.Backward == null) { node.Forward = header; @@ -274,7 +301,9 @@ private void MakeUsed(CacheNode node) { node.Backward.Forward = null; tail = node.Backward; + node.Forward = header; + node.Backward = null; header.Backward = node; header = node; } @@ -283,6 +312,7 @@ private void MakeUsed(CacheNode node) node.Backward.Forward = node.Forward; node.Forward.Backward = node.Backward; node.Forward = header; + node.Backward = null; header.Backward = node; header = node; } From 0c05cc49394c0232ca9a6154d985e71ed3059c92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Wed, 17 Jan 2018 15:01:34 +0800 Subject: [PATCH 88/91] lrucache update --- .../Support/LruCache/LruCacheTests.cs | 11 +++++++++++ src/CatLib.Core/Support/LruCache/LruCache.cs | 17 +++++++++++++---- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/CatLib.Core.Tests/Support/LruCache/LruCacheTests.cs b/src/CatLib.Core.Tests/Support/LruCache/LruCacheTests.cs index 4969984..b982c46 100644 --- a/src/CatLib.Core.Tests/Support/LruCache/LruCacheTests.cs +++ b/src/CatLib.Core.Tests/Support/LruCache/LruCacheTests.cs @@ -35,6 +35,17 @@ public void AddTest() } } + /// + /// 单元素测试 + /// + [TestMethod] + public void OnecElementTests() + { + var cache = new LruCache(5); + cache.Add("1", "2"); + cache.Remove("1"); + } + /// /// 获取测试 /// diff --git a/src/CatLib.Core/Support/LruCache/LruCache.cs b/src/CatLib.Core/Support/LruCache/LruCache.cs index bcd2382..dfbea21 100644 --- a/src/CatLib.Core/Support/LruCache/LruCache.cs +++ b/src/CatLib.Core/Support/LruCache/LruCache.cs @@ -165,18 +165,27 @@ public void Remove(TKey key) if (result == tail) { tail = result.Backward; - tail.Forward = null; + if (tail != null) + { + tail.Forward = null; + } } - else if (result == header) + + if (result == header) { header = result.Forward; - header.Backward = null; + if (header != null) + { + header.Backward = null; + } } - else if (result.Backward != null) + + if (result.Backward != null && result.Forward != null) { result.Backward.Forward = result.Forward; result.Forward.Backward = result.Backward; } + count--; } From 680ecf01fe622e90e5a26f6f86bdf9f9b6c16ef1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Sat, 20 Jan 2018 14:52:12 +0800 Subject: [PATCH 89/91] container update --- .../Container/ContainerPerformanceTests.cs | 160 ++++++++++++++++++ .../Support/Container/ContainerTests.cs | 144 ++++++++++++++++ .../Support/Container/Container.cs | 128 +++++++++----- .../Support/Container/IContainer.cs | 2 +- 4 files changed, 395 insertions(+), 39 deletions(-) diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerPerformanceTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerPerformanceTests.cs index 08be288..609e33a 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerPerformanceTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerPerformanceTests.cs @@ -56,5 +56,165 @@ public void TestCreateInstance() Activator.CreateInstance(typeof(TestSerializeClass), new object[]{}); }, 1000000); } + + public class TestMakeHandClass + { + public TestMakeHandClass(TestSerializeClass cls) + { + + } + } + + public class TestMakeClass : ITestMakeClass + { + public TestMakeClass(TestSerializeClass cls) + { + + } + } + + public class TestMakeClass2 + { + public TestMakeClass2(TestSerializeClass cls) + { + + } + } + + public class TestMakeNullParamsClass : ITestMakeNullParamsClass + { + public TestMakeNullParamsClass() + { + + } + } + + public interface ITestMakeClass { } + public interface ITestMakeNullParamsClass { } + + [TestMethod] + public void TestSingleMake() + { + var container = new Container(); + container.Singleton((_, __) => new TestMakeHandClass(null)); + container.Singleton(); + container.Singleton(); + container.Singleton().Alias(); + + Watch("TestSingleMake(非反射) 1000000次", () => + { + container.Make(); + }, 1000000); + + Watch("TestSingleMake(反射,依赖注入) 1000000次", () => + { + container.Make(); + }, 1000000); + + Watch("TestSingleMake(反射,无注入) 1000000次", () => + { + container.Make(); + }, 1000000); + } + + [TestMethod] + public void TestBindMake() + { + var container = new Container(); + container.Bind((_, __) => new TestMakeHandClass(null)); + container.Singleton(); + container.Bind().Alias(); + container.Bind().Alias(); + + Watch("TestBindMake(非反射) 1000000次", () => + { + container.Make(); + }, 1000000); + + Watch("TestBindMake(反射,依赖注入) 1000000次", () => + { + container.Make(); + }, 1000000); + + Watch("TestBindMake(反射,无注入) 1000000次", () => + { + container.Make(); + }, 1000000); + } + + public class TestMakeClassFacade : Facade + { + + } + + public class TestMakeClassNoParamsFacade : Facade + { + + } + + public abstract class OriginalFacade where TInterface : new() + { + private static TInterface instance; + /// + /// 门面实例 + /// + public static TInterface Instance + { + get + { + if (instance != null) + { + return instance; + } + + return instance = new TInterface(); + } + } + } + + public class TestOriginalFacade : OriginalFacade + { + } + + [TestMethod] + public void TestOriginalFacadeSpeed() + { + Watch("TestOriginalFacadeSpeed() 1000000次", () => + { + var obj = TestOriginalFacade.Instance; + }, 1000000); + } + + [TestMethod] + public void TestSingletonFacade() + { + var container = new Application(); + container.Singleton(); + container.Singleton().Alias(); + + Watch("TestSingletonFacade() 1000000次", () => + { + var obj = TestMakeClassFacade.Instance; + }, 1000000); + } + + [TestMethod] + public void TestBindFacade() + { + var container = new Application(); + container.Singleton(); + container.Bind().Alias(); + container.Bind().Alias(); + + Watch("TestBindFacade() 1000000次", () => + { + var obj = TestMakeClassFacade.Instance; + }, 1000000); + + Watch("TestBindFacade(无参数) 1000000次", () => + { + var obj = TestMakeClassNoParamsFacade.Instance; + }, 1000000); + } } } diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs index de791ba..0af74b7 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs @@ -1612,6 +1612,150 @@ public void TestDisposableRelease() } #endregion + [TestMethod] + public void TestOneWatch() + { + var container = MakeContainer(); + + var b = container.Bind((c, p) => 123); + var obj = container.Make(); + Assert.AreEqual(123, obj); + + b.Unbind(); + + object ins1 = null; + container.Watch((instance) => + { + ins1 = instance; + }); + container.Bind((c, p) => new object()); + + Assert.AreNotEqual(null, ins1); + } + + [TestMethod] + public void TestNullBindWatch() + { + var container = MakeContainer(); + container.Instance(123); + + object ins1 = null, ins2 = null; + container.Watch((instance) => + { + ins1 = instance; + }); + container.Watch((instance) => + { + ins2 = instance; + }); + var obj = new object(); + container.Instance(obj); + + Assert.AreSame(obj, ins1); + Assert.AreEqual(obj, ins1); + Assert.AreSame(obj, ins2); + Assert.AreEqual(obj, ins2); + } + + [TestMethod] + public void TestBindWatch() + { + var container = MakeContainer(); + + var b = container.Bind((c, p) => 123); + var obj = container.Make(); + Assert.AreEqual(123, obj); + + b.Unbind(); + + object ins1 = null,ins2 = null; + container.Watch((instance) => + { + ins1 = instance; + }); + container.Watch((instance) => + { + ins2 = instance; + }); + container.Bind((c, p) => new object()); + + Assert.AreNotSame(ins1, ins2); + } + + [TestMethod] + public void TestSingletonWatch() + { + var container = MakeContainer(); + + var b = container.Singleton((c, p) => 123); + var obj = container.Make(); + Assert.AreEqual(123, obj); + + b.Unbind(); + + object ins1 = null, ins2 = null; + container.Watch((instance) => + { + ins1 = instance; + }); + container.Watch((instance) => + { + ins2 = instance; + }); + container.Singleton((c, p) => new object()); + + Assert.AreSame(ins1, ins2); + } + + [TestMethod] + public void TestNullFlash() + { + var container = MakeContainer(); + container.Flash(() => + { + }, null); + + // no throw error is success + } + + [TestMethod] + public void TestEmptyFlash() + { + var container = MakeContainer(); + container.Flash(() => + { + }, new KeyValuePair[] { }); + + // no throw error is success + } + + [TestMethod] + public void TestFlashRecursive() + { + var container = MakeContainer(); + + var call = 0; + container.Flash(() => + { + call++; + Assert.AreEqual(1, container.Make("hello")); + Assert.AreEqual(2, container.Make("world")); + container.Flash(() => + { + call++; + Assert.AreEqual(10, container.Make("hello")); + Assert.AreEqual(2, container.Make("world")); + }, new KeyValuePair("hello", 10)); + Assert.AreEqual(1, container.Make("hello")); + Assert.AreEqual(2, container.Make("world")); + },new KeyValuePair("hello", 1) + , new KeyValuePair("world", 2)); + + Assert.AreEqual(false, container.HasInstance("hello")); + Assert.AreEqual(false, container.HasInstance("world")); + Assert.AreEqual(2, call); + } + [TestMethod] public void OnResolvingExistsObject() { diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 45e5a4a..80c3583 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -305,7 +305,7 @@ public bool IsAlias(string name) } /// - /// 为服务设定一个别名 + /// 以全局的方式为服务设定一个别名 /// /// 别名 /// 映射到的服务名 @@ -445,7 +445,16 @@ public IBindData Bind(string service, Func concret if (IsResolved(service)) { - TriggerOnRebound(service); + if (isStatic) + { + // 如果为 静态的 那么直接解决这个服务 + // 在服务静态化的过程会触发 TriggerOnRebound + Resolve(service); + } + else + { + TriggerOnRebound(service); + } } return bindData; @@ -589,7 +598,7 @@ public object Instance(string service, object instance) if (isResolved) { - TriggerOnRebound(service); + TriggerOnRebound(service, instance); } return instance; @@ -809,23 +818,59 @@ public void Flash(Action callback, params KeyValuePair[] service { lock (syncRoot) { - foreach (var service in services) + if (services == null || services.Length <= 0) { - if (HasInstance(service.Key)) + callback(); + return; + } + + Stack> serviceStack = null; + try + { + foreach (var service in services) { - throw new RuntimeException("Flash service [" + service.Key + "] is already exists."); + try + { + // 如果服务被绑定过了,那么我们认为这不是一个Flash可用的服务 + // 所以我们抛出一个异常来终止该操作。 + if (HasBind(service.Key)) + { + throw new RuntimeException("Flash service [" + service.Key + + "] name has be used for bind or alias."); + } + } + catch + { + // 如果在 HasBind 执行过程中出现了异常,那么清空服务堆栈 + // 因为服务还没替换也无需在执行还原操作。 + serviceStack = null; + throw; + } + + if (!HasInstance(service.Key)) + { + continue; + } + + // 如果服务已经存在那么,将旧的服务加入堆栈。 + // 等待Flash操作完成后再恢复旧的服务实例。 + serviceStack = serviceStack ?? new Stack>(services.Length); + serviceStack.Push(new KeyValuePair(service.Key, Make(service.Key))); } - if (HasBind(service.Key)) + Arr.Flash(services, + service => Instance(service.Key, service.Value), + service => Release(service.Key), + callback); + } + finally + { + while (serviceStack != null && serviceStack.Count > 0) { - throw new RuntimeException("Flash service [" + service.Key + "] name has be used for bind or alias."); + var service = serviceStack.Pop(); + Instance(service.Key, service.Value); } } - - Arr.Flash(services, - service => Instance(service.Key, service.Value), - service => Release(service.Key), - callback); } } @@ -1490,35 +1535,46 @@ private void TriggerOnRelease(IBindData bindData, object obj) } /// - /// 释放实例 + /// 触发服务重定义事件 /// - /// 实例 - private void DisposeInstance(object obj) + /// 发生重定义的服务 + /// 服务实例(如果为空将会从容器请求) + private void TriggerOnRebound(string service, object instance = null) { - var disposable = obj as IDisposable; - if (disposable != null) + var callbacks = GetOnReboundCallbacks(service); + if (callbacks == null || callbacks.Count <= 0) { - disposable.Dispose(); + return; } - } - /// - /// 触发服务重定义事件 - /// - /// 发生重定义的服务 - private void TriggerOnRebound(string service) - { - var instance = Make(service); var bind = GetBind(service); - + instance = instance ?? Make(service); Flash(() => + { + for (var index = 0; index < callbacks.Count; index++) { - foreach (var callback in GetOnReboundCallbacks(service)) + callbacks[index](instance); + // 如果是非实例绑定那么每个 callback 给定单独的实例 + if (index + 1 < callbacks.Count && (bind == null || !bind.IsStatic)) { - callback.Invoke(instance); + instance = Make(service); } - }, Pair(typeof(IBindData), bind), - Pair(typeof(BindData), bind)); + } + }, Pair(typeof(IBindData), bind), + Pair(typeof(BindData), bind)); + } + + /// + /// 释放实例 + /// + /// 实例 + private void DisposeInstance(object obj) + { + var disposable = obj as IDisposable; + if (disposable != null) + { + disposable.Dispose(); + } } /// @@ -1536,14 +1592,10 @@ private KeyValuePair Pair(Type type, object instance) /// 获取重定义的服务所对应的回调 /// /// 回调列表 - private IEnumerable> GetOnReboundCallbacks(string service) + private IList> GetOnReboundCallbacks(string service) { List> result; - if (!rebound.TryGetValue(service, out result)) - { - return new Action[] { }; - } - return result; + return !rebound.TryGetValue(service, out result) ? null : result; } /// diff --git a/src/CatLib.Core/Support/Container/IContainer.cs b/src/CatLib.Core/Support/Container/IContainer.cs index a7f8ef9..6cc7ce6 100644 --- a/src/CatLib.Core/Support/Container/IContainer.cs +++ b/src/CatLib.Core/Support/Container/IContainer.cs @@ -206,7 +206,7 @@ public interface IContainer Func Factory(string service, params object[] userParams); /// - /// 为服务设定一个别名 + /// 以全局的方式为服务设定一个别名 /// /// 别名 /// 映射到的服务名 From 145d4e03ce7f9865498aed241dfb75b618313b5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Sat, 20 Jan 2018 15:26:24 +0800 Subject: [PATCH 90/91] remove lrucache --- .../CatLib.Core.NetStandard.csproj | 4 - .../CatLib.Core.Tests.csproj | 1 - .../CatLib/ApplicationTests.cs | 4 +- .../Support/LruCache/LruCacheTests.cs | 241 ------------- src/CatLib.Core/CatLib.Core.csproj | 3 - src/CatLib.Core/Support/Events/Dispatcher.cs | 2 +- src/CatLib.Core/Support/LruCache/CacheNode.cs | 55 --- src/CatLib.Core/Support/LruCache/ILruCache.cs | 65 ---- src/CatLib.Core/Support/LruCache/LruCache.cs | 330 ------------------ 9 files changed, 3 insertions(+), 702 deletions(-) delete mode 100644 src/CatLib.Core.Tests/Support/LruCache/LruCacheTests.cs delete mode 100644 src/CatLib.Core/Support/LruCache/CacheNode.cs delete mode 100644 src/CatLib.Core/Support/LruCache/ILruCache.cs delete mode 100644 src/CatLib.Core/Support/LruCache/LruCache.cs diff --git a/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj b/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj index 460a801..8d4a8d8 100644 --- a/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj +++ b/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj @@ -91,9 +91,6 @@ - - - @@ -127,7 +124,6 @@ - diff --git a/src/CatLib.Core.Tests/CatLib.Core.Tests.csproj b/src/CatLib.Core.Tests/CatLib.Core.Tests.csproj index 41c945f..b01e6aa 100644 --- a/src/CatLib.Core.Tests/CatLib.Core.Tests.csproj +++ b/src/CatLib.Core.Tests/CatLib.Core.Tests.csproj @@ -46,7 +46,6 @@ - diff --git a/src/CatLib.Core.Tests/CatLib/ApplicationTests.cs b/src/CatLib.Core.Tests/CatLib/ApplicationTests.cs index d422755..7be5d7d 100644 --- a/src/CatLib.Core.Tests/CatLib/ApplicationTests.cs +++ b/src/CatLib.Core.Tests/CatLib/ApplicationTests.cs @@ -120,9 +120,9 @@ public void GetVersionTest() public void MakeAssemblyClass() { var app = new Application(); - var lru = app.Make>(10); + var sortSet = app.Make>(); - Assert.AreNotEqual(null, lru); + Assert.AreNotEqual(null, sortSet); } [TestMethod] diff --git a/src/CatLib.Core.Tests/Support/LruCache/LruCacheTests.cs b/src/CatLib.Core.Tests/Support/LruCache/LruCacheTests.cs deleted file mode 100644 index b982c46..0000000 --- a/src/CatLib.Core.Tests/Support/LruCache/LruCacheTests.cs +++ /dev/null @@ -1,241 +0,0 @@ -/* - * 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 Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace CatLib.Tests.Stl -{ - [TestClass] - public class LruCacheTests - { - /// - /// 增加测试 - /// - [TestMethod] - public void AddTest() - { - var cache = new LruCache(5); - for (var i = 0; i < 5; i++) - { - cache.Add(i.ToString(), i.ToString()); - } - - var n = 5; - foreach (var v in cache) - { - Assert.AreEqual((--n).ToString(), v.Value); - } - } - - /// - /// 单元素测试 - /// - [TestMethod] - public void OnecElementTests() - { - var cache = new LruCache(5); - cache.Add("1", "2"); - cache.Remove("1"); - } - - /// - /// 获取测试 - /// - [TestMethod] - public void GetTest() - { - var cache = new LruCache(5); - for (var i = 0; i < 5; i++) - { - cache.Add(i.ToString(), i.ToString()); - } - - var result = cache["0"]; - result = cache["1"]; - - if (result == null) - { - Assert.Fail(); - } - - foreach (var v in new[] { "1", "0", "4", "3", "2" }) - { - Assert.AreEqual(v, cache[v]); - } - } - - /// - /// 覆盖测试 - /// - [TestMethod] - public void ReplaceTest() - { - var cache = new LruCache(5); - for (var i = 0; i < 5; i++) - { - cache.Add(i.ToString(), i.ToString()); - } - - cache["0"] = "10"; - cache["1"] = "11"; - - foreach (var v in new[] { "1", "0", "4", "3", "2" }) - { - if (v == "0") - { - Assert.AreEqual("10", cache[v]); - } - else if (v == "1") - { - Assert.AreEqual("11", cache[v]); - } - else - { - Assert.AreEqual(v, cache[v]); - } - } - } - - /// - /// 测试移除事件 - /// - [TestMethod] - public void TestRemoveEvent() - { - var cache = new LruCache(5); - for (var i = 0; i < 5; i++) - { - cache.Add(i.ToString(), i.ToString()); - } - - var callNum = 0; - cache.OnRemoveLeastUsed += (key, val) => - { - if (callNum++ <= 0) - { - cache.Get(key); - } - }; - cache.Add("10", "10"); - - Assert.AreEqual(default(string), cache.Get("1")); - Assert.AreEqual(5, cache.Count); - Assert.AreEqual(1, callNum); - } - - /// - /// 末尾移除测试 - /// - [TestMethod] - public void RemoveLastedTest() - { - var cache = new LruCache(5); - for (var i = 0; i < 5; i++) - { - cache.Add(i.ToString(), i.ToString()); - } - cache["0"] = "0"; - cache["1"] = "1"; - cache.Add("999", "999"); - - Assert.AreEqual(5, cache.Count); - foreach (var v in new[] { "999", "1", "0", "4", "3" }) - { - Assert.AreEqual(v, cache[v]); - } - } - - /// - /// 获取不存在元素的测试 - /// - [TestMethod] - public void GetNotExistsKey() - { - var cache = new LruCache(5); - Assert.AreEqual(null, cache["123"]); - Assert.AreEqual("notExists", cache.Get("111", "notExists")); - } - - /// - /// 移除测试 - /// - [TestMethod] - public void RemoveTest() - { - var cache = new LruCache(5); - for (var i = 0; i < 5; i++) - { - cache.Add(i.ToString(), i.ToString()); - } - - foreach (var v in new[] { "2", "1", "3" }) - { - cache.Remove(v); - } - - foreach (var v in new[] { "4", "0" }) - { - Assert.AreEqual(v, cache[v]); - } - - Assert.AreEqual(2, cache.Count); - } - - /// - /// 在头部和尾部移除 - /// - [TestMethod] - public void RemoveWithHeaderAndTail() - { - var cache = new LruCache(5); - for (var i = 0; i < 5; i++) - { - cache.Add(i.ToString(), i.ToString()); - } - - foreach (var v in new[] { "0", "2", "4" }) - { - cache.Remove(v); - } - - foreach (var v in new[] { "3", "1" }) - { - Assert.AreEqual(v, cache[v]); - } - - Assert.AreEqual(2, cache.Count); - } - - /// - /// 移除不存在的元素 - /// - [TestMethod] - public void RemoveNotExists() - { - var cache = new LruCache(5); - cache.Remove("999"); - } - - [TestMethod] - public void TestGet() - { - var cache = new LruCache(5); - cache.Add("10", "5"); - - string val; - Assert.AreEqual(true, cache.Get("10", out val, "100")); - Assert.AreEqual("5", val); - - Assert.AreEqual(false, cache.Get("11", out val, "100")); - Assert.AreEqual("100", val); - } - } -} diff --git a/src/CatLib.Core/CatLib.Core.csproj b/src/CatLib.Core/CatLib.Core.csproj index 65abff4..1b15f77 100644 --- a/src/CatLib.Core/CatLib.Core.csproj +++ b/src/CatLib.Core/CatLib.Core.csproj @@ -74,9 +74,6 @@ - - - diff --git a/src/CatLib.Core/Support/Events/Dispatcher.cs b/src/CatLib.Core/Support/Events/Dispatcher.cs index 3808652..d88b3c8 100644 --- a/src/CatLib.Core/Support/Events/Dispatcher.cs +++ b/src/CatLib.Core/Support/Events/Dispatcher.cs @@ -229,7 +229,7 @@ protected virtual IEvent MakeEvent(string eventName, object target, MethodInfo m /// 事件监听器 protected virtual Func MakeListener(object target, MethodInfo method, bool isWildcard = false) { - return (eventName, payloads) => container.Call(target, method, isWildcard + return (eventName, payloads) => Container.Call(target, method, isWildcard ? Arr.Merge(new object[] { eventName }, payloads) : payloads); } diff --git a/src/CatLib.Core/Support/LruCache/CacheNode.cs b/src/CatLib.Core/Support/LruCache/CacheNode.cs deleted file mode 100644 index d75c501..0000000 --- a/src/CatLib.Core/Support/LruCache/CacheNode.cs +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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.Collections.Generic; - -namespace CatLib -{ - /// - /// 缓存节点 - /// - internal sealed class CacheNode - { - /// - /// 键值 - /// - public KeyValuePair KeyValue { get; private set; } - - /// - /// 上一个节点 - /// - public CacheNode Backward { get; set; } - - /// - /// 下一个节点 - /// - public CacheNode Forward { get; set; } - - /// - /// 创建一个缓存节点 - /// - /// 键 - /// 值 - public CacheNode(TKey key, TVal val) - { - KeyValue = new KeyValuePair(key, val); - } - - /// - /// 替换元素 - /// - /// 值 - public void Replace(TVal val) - { - KeyValue = new KeyValuePair(KeyValue.Key, val); - } - } -} \ No newline at end of file diff --git a/src/CatLib.Core/Support/LruCache/ILruCache.cs b/src/CatLib.Core/Support/LruCache/ILruCache.cs deleted file mode 100644 index a382191..0000000 --- a/src/CatLib.Core/Support/LruCache/ILruCache.cs +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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.Collections.Generic; - -namespace CatLib -{ - /// - /// Lru缓存 - /// - /// 键的类型 - /// 值的类型 - public interface ILruCache : IEnumerable> - { - /// - /// 在lru缓存中增加一个元素 - /// - /// 键 - /// 值 - void Add(TKey key, TVal value); - - /// - /// 根据key获取val,如果被淘汰则返回传入的默认值 - /// - /// 键 - /// 默认返回值 - /// - TVal Get(TKey key, TVal defaultValue = default(TVal)); - - /// - /// 根据key获取val,如果被淘汰则返回传入的默认值 - /// - /// 键 - /// 值 - /// 默认值 - /// 是否获取 - bool Get(TKey key, out TVal val, TVal defaultVal = default(TVal)); - - /// - /// 移除元素 - /// - /// 键 - void Remove(TKey key); - - /// - /// 获取Lru缓存中的元素数量 - /// - int Count { get; } - - /// - /// 根据key获取val,如果被淘汰则返回默认值 - /// - /// 键 - /// - TVal this[TKey key] { get; } - } -} \ No newline at end of file diff --git a/src/CatLib.Core/Support/LruCache/LruCache.cs b/src/CatLib.Core/Support/LruCache/LruCache.cs deleted file mode 100644 index dfbea21..0000000 --- a/src/CatLib.Core/Support/LruCache/LruCache.cs +++ /dev/null @@ -1,330 +0,0 @@ -/* - * 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; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; - -namespace CatLib -{ - /// - /// 近期最少使用缓存 - /// - [DebuggerDisplay("Count = {Count}")] - public sealed class LruCache : ILruCache - { - /// - /// 最大容量 - /// - private readonly int maxCapacity; - - /// - /// 头节点 - /// - private CacheNode header; - - /// - /// 尾节点 - /// - private CacheNode tail; - - /// - /// 当移除最后使用的元素之前 - /// - public event Action OnRemoveLeastUsed; - - /// - /// 近期最少使用缓存迭代器 - /// - private struct Enumerator : IEnumerable> - { - /// - /// 近期最少使用缓存 - /// - private readonly LruCache lruCache; - - /// - /// 构造一个迭代器 - /// - /// 近期最少使用缓存 - internal Enumerator(LruCache lruCache) - { - this.lruCache = lruCache; - } - - /// - /// 迭代器 - /// - /// 元素迭代器 - public IEnumerator> GetEnumerator() - { - var cursor = lruCache.header; - while (cursor != null) - { - yield return cursor.KeyValue; - cursor = cursor.Forward; - } - } - - /// - /// 获取迭代器 - /// - /// 迭代器 - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - } - - /// - /// 元素计数 - /// - private int count; - - /// - /// 创建一个Lru缓存 - /// - public LruCache(int maxCapacity) - { - Guard.Requires(maxCapacity > 0); - this.maxCapacity = maxCapacity; - count = 0; - } - - /// - /// 在lru缓存中增加一个元素,如果元素已经存在则会替换元素 - /// - /// 键 - /// 值 - public void Add(TKey key, TVal value) - { - Guard.Requires(key != null); - var result = header; - while (result != null) - { - if (result.KeyValue.Key.Equals(key)) - { - result.Replace(value); - MakeUsed(result); - return; - } - result = result.Forward; - } - - if (count >= maxCapacity) - { - RemoveLeastUsed(); - } - - var addedNode = new CacheNode(key, value); - - if (header == null) - { - header = addedNode; - tail = addedNode; - } - else - { - MakeUsed(addedNode); - } - - count++; - } - - /// - /// 移除元素 - /// - /// 键 - public void Remove(TKey key) - { - Guard.Requires(key != null); - var result = header; - while (result != null) - { - if (result.KeyValue.Key.Equals(key)) - { - break; - } - result = result.Forward; - } - - if (result == null) - { - return; - } - - if (result == tail) - { - tail = result.Backward; - if (tail != null) - { - tail.Forward = null; - } - } - - if (result == header) - { - header = result.Forward; - if (header != null) - { - header.Backward = null; - } - } - - if (result.Backward != null && result.Forward != null) - { - result.Backward.Forward = result.Forward; - result.Forward.Backward = result.Backward; - } - - count--; - } - - /// - /// 根据key获取val,如果被淘汰则返回传入的默认值 - /// - /// 键 - /// 默认返回值 - /// - public TVal Get(TKey key, TVal defaultValue = default(TVal)) - { - TVal result; - Get(key, out result, defaultValue); - return result; - } - - /// - /// 根据key获取val,如果被淘汰则返回传入的默认值 - /// - /// 键 - /// 值 - /// 默认值 - /// 是否获取 - public bool Get(TKey key, out TVal val, TVal defaultVal = default(TVal)) - { - Guard.Requires(key != null); - var result = header; - while (result != null) - { - if (result.KeyValue.Key.Equals(key)) - { - break; - } - result = result.Forward; - } - - if (result == null) - { - val = defaultVal; - return false; - } - - MakeUsed(result); - val = result.KeyValue.Value; - return true; - } - - /// - /// 获取Lru缓存中的元素数量 - /// - public int Count - { - get { return count; } - } - - /// - /// 根据key获取val,如果被淘汰则返回默认值 - /// - /// 键 - /// - public TVal this[TKey key] - { - get { return Get(key); } - set { Add(key, value); } - } - - /// - /// 迭代器 - /// - /// 迭代器 - public IEnumerator> GetEnumerator() - { - return new Enumerator(this).GetEnumerator(); - } - - /// - /// 迭代器 - /// - /// 迭代器 - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - /// - /// 移除最后一个元素 - /// - private void RemoveLeastUsed() - { - if (OnRemoveLeastUsed != null) - { - OnRemoveLeastUsed.Invoke(tail.KeyValue.Key, tail.KeyValue.Value); - } - - tail.Backward.Forward = null; - tail = tail.Backward; - count--; - } - - /// - /// 激活指定节点为最近使用 - /// - /// 节点 - private void MakeUsed(CacheNode node) - { - if (node == header) - { - return; - } - - if (node.Forward == null && node.Backward == null) - { - node.Forward = header; - header.Backward = node; - if (header.Forward == null) - { - tail = header; - } - header = node; - } - else if (node.Forward == null && node.Backward != null) - { - node.Backward.Forward = null; - tail = node.Backward; - - node.Forward = header; - node.Backward = null; - header.Backward = node; - header = node; - } - else if (node.Forward != null && node.Backward != null) - { - node.Backward.Forward = node.Forward; - node.Forward.Backward = node.Backward; - node.Forward = header; - node.Backward = null; - header.Backward = node; - header = node; - } - } - } -} \ No newline at end of file From 17494feeb624b8e13430170abc7ba8ae15514730 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Sat, 20 Jan 2018 16:32:56 +0800 Subject: [PATCH 91/91] facade add binder check --- src/CatLib.Core/CatLib/Facade.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/CatLib.Core/CatLib/Facade.cs b/src/CatLib.Core/CatLib/Facade.cs index 257c9d8..85e1a73 100644 --- a/src/CatLib.Core/CatLib/Facade.cs +++ b/src/CatLib.Core/CatLib/Facade.cs @@ -84,7 +84,13 @@ private static TService Make() if (binder == null || binder != newBinder) { - newBinder.OnRelease((_, __) => instance = default(TService)); + newBinder.OnRelease((oldBinder, __) => + { + if (oldBinder == binder) + { + instance = default(TService); + } + }); binder = newBinder; }