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