Skip to content

Commit 539db23

Browse files
committed
resolved #98
1 parent 94fd752 commit 539db23

File tree

5 files changed

+205
-4
lines changed

5 files changed

+205
-4
lines changed

src/CatLib.Core.Tests/Support/Container/GivenDataTests.cs

Lines changed: 111 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,120 @@ public void CheckGivenIllegalValue()
5252

5353
ExceptionAssert.Throws<ArgumentNullException>(() =>
5454
{
55-
givenData.Given(null);
55+
givenData.Given(string.Empty);
5656
});
57-
ExceptionAssert.Throws<ArgumentNullException>(() =>
57+
}
58+
59+
60+
private class TestGivenClosureClass
61+
{
62+
public string Name { get; set; }
63+
public int Value { get; set; }
64+
public TestGivenClosureClass(string name, int value = 0)
5865
{
59-
givenData.Given(string.Empty);
66+
Name = name;
67+
Value = value;
68+
}
69+
}
70+
71+
[TestMethod]
72+
public void TestGivenClosure()
73+
{
74+
var container = new Container();
75+
container.Bind<TestGivenClosureClass>().Needs<string>().Given(() => "hello world")
76+
.Needs<int>().Given(()=> 10);
77+
78+
Assert.AreEqual("hello world", container.Make<TestGivenClosureClass>().Name);
79+
Assert.AreEqual(10, container.Make<TestGivenClosureClass>().Value);
80+
}
81+
82+
[TestMethod]
83+
[ExpectedException(typeof(LogicException))]
84+
public void TestGivenDuplicateValue()
85+
{
86+
var container = new Container();
87+
container.Bind<TestGivenClosureClass>().Needs<string>().Given(() => "hello world");
88+
container.Bind<TestGivenClosureClass>().Needs<string>().Given(() => "ddd");
89+
}
90+
91+
[TestMethod]
92+
[ExpectedException(typeof(LogicException))]
93+
public void TestGivenDuplicateValue2()
94+
{
95+
var container = new Container();
96+
container.Bind<TestGivenClosureClass>().Needs<string>().Given(() => "hello world");
97+
container.Bind<TestGivenClosureClass>().Needs<string>().Given<int>();
98+
}
99+
100+
[TestMethod]
101+
[ExpectedException(typeof(LogicException))]
102+
public void TestGivenDuplicateValue3()
103+
{
104+
var container = new Container();
105+
container.Bind<TestGivenClosureClass>().Needs<string>().Given<int>();
106+
container.Bind<TestGivenClosureClass>().Needs<string>().Given(() => "hello world");
107+
}
108+
109+
[TestMethod]
110+
[ExpectedException(typeof(LogicException))]
111+
public void TestGivenDuplicateValue4()
112+
{
113+
var container = new Container();
114+
container.Bind<TestGivenClosureClass>().Needs<string>().Given<int>();
115+
container.Bind<TestGivenClosureClass>().Needs<string>().Given<long>();
116+
}
117+
118+
[TestMethod]
119+
[ExpectedException(typeof(LogicException))]
120+
public void TestGivenDuplicateValue5()
121+
{
122+
var container = new Container();
123+
container.Bind<TestGivenClosureClass>().Needs<string>().Given(() => "hello world");
124+
container.Bind<TestGivenClosureClass>().Needs<long>().Given<long>();
125+
container.Bind<TestGivenClosureClass>().Needs<string>().Given<long>();
126+
}
127+
128+
[TestMethod]
129+
[ExpectedException(typeof(LogicException))]
130+
public void TestGivenDuplicateValue6()
131+
{
132+
var container = new Container();
133+
container.Bind<TestGivenClosureClass>().Needs<string>().Given<int>();
134+
container.Bind<TestGivenClosureClass>().Needs<long>().Given(() => "hello world");
135+
container.Bind<TestGivenClosureClass>().Needs<string>().Given(() => "hello world");
136+
}
137+
138+
[TestMethod]
139+
[ExpectedException(typeof(AssertException))]
140+
public void TestGivenClosureException()
141+
{
142+
var container = new Container();
143+
container.Bind<TestGivenClosureClass>().Needs<string>().Given(() =>
144+
{
145+
throw new AssertException("hello world");
60146
});
147+
148+
container.Make<TestGivenClosureClass>();
149+
}
150+
151+
private class TestGivenClosureAttrClass
152+
{
153+
[Inject]
154+
public string Name { get; set; }
155+
156+
[Inject]
157+
public int Value { get; set; }
158+
}
159+
160+
[TestMethod]
161+
public void TestGivenAttrClosure()
162+
{
163+
var container = new Container();
164+
container.Bind<TestGivenClosureAttrClass>().Needs<string>().Given(() => "hello world")
165+
.Needs<int>().Given(() => 10);
166+
167+
Assert.AreEqual("hello world", container.Make<TestGivenClosureAttrClass>().Name);
168+
Assert.AreEqual(10, container.Make<TestGivenClosureAttrClass>().Value);
61169
}
62170
}
63171
}

src/CatLib.Core/Support/Container/Bindable.cs

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
* Document: http://catlib.io/
1010
*/
1111

12+
using System;
1213
using System.Collections.Generic;
1314

1415
namespace CatLib
@@ -34,6 +35,12 @@ public abstract class Bindable : IBindable
3435
/// </summary>
3536
private Dictionary<string, string> contextual;
3637

38+
/// <summary>
39+
/// 服务上下文闭包
40+
/// 当前服务需求某个服务时给定的闭包
41+
/// </summary>
42+
private Dictionary<string, Func<object>> contextualClosure;
43+
3744
/// <summary>
3845
/// 同步锁
3946
/// </summary>
@@ -83,14 +90,38 @@ internal void AddContextual(string needs, string given)
8390
{
8491
contextual = new Dictionary<string, string>();
8592
}
86-
if (contextual.ContainsKey(needs))
93+
if (contextual.ContainsKey(needs)
94+
|| (contextualClosure != null && contextualClosure.ContainsKey(needs)))
8795
{
8896
throw new LogicException($"Needs [{needs}] is already exist.");
8997
}
9098
contextual.Add(needs, given);
9199
}
92100
}
93101

102+
/// <summary>
103+
/// 为服务增加上下文
104+
/// </summary>
105+
/// <param name="needs">需求什么服务</param>
106+
/// <param name="given">给与什么服务</param>
107+
internal void AddContextual(string needs, Func<object> given)
108+
{
109+
lock (SyncRoot)
110+
{
111+
GuardIsDestroy();
112+
if (contextualClosure == null)
113+
{
114+
contextualClosure = new Dictionary<string, Func<object>>();
115+
}
116+
if (contextualClosure.ContainsKey(needs)
117+
|| (contextual != null && contextual.ContainsKey(needs)))
118+
{
119+
throw new LogicException($"Needs [{needs}] is already exist.");
120+
}
121+
contextualClosure.Add(needs, given);
122+
}
123+
}
124+
94125
/// <summary>
95126
/// 获取上下文的需求关系
96127
/// </summary>
@@ -105,6 +136,20 @@ internal string GetContextual(string needs)
105136
return contextual.TryGetValue(needs, out string contextualNeeds) ? contextualNeeds : needs;
106137
}
107138

139+
/// <summary>
140+
/// 获取上下文关系闭包实现
141+
/// </summary>
142+
/// <param name="needs">需求的服务</param>
143+
/// <returns>给与的闭包</returns>
144+
internal Func<object> GetContextualClosure(string needs)
145+
{
146+
if (contextualClosure == null)
147+
{
148+
return null;
149+
}
150+
return contextualClosure.TryGetValue(needs, out Func<object> closure) ? closure : null;
151+
}
152+
108153
/// <summary>
109154
/// 解除绑定
110155
/// </summary>

src/CatLib.Core/Support/Container/Container.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1150,6 +1150,12 @@ protected virtual string GetParamNeedsService(ParameterInfo baseParam)
11501150
/// <returns>解决结果</returns>
11511151
protected virtual object ResolveAttrPrimitive(Bindable makeServiceBindData, string service, PropertyInfo baseParam)
11521152
{
1153+
var contextualClosure = makeServiceBindData.GetContextualClosure(service);
1154+
if (contextualClosure != null)
1155+
{
1156+
return contextualClosure();
1157+
}
1158+
11531159
service = makeServiceBindData.GetContextual(service);
11541160
if (CanMake(service))
11551161
{
@@ -1174,8 +1180,15 @@ protected virtual object ResolveAttrPrimitive(Bindable makeServiceBindData, stri
11741180
/// <returns>解决结果</returns>
11751181
protected virtual object ResloveAttrClass(Bindable makeServiceBindData, string service, PropertyInfo baseParam)
11761182
{
1183+
var contextualClosure = makeServiceBindData.GetContextualClosure(service);
1184+
if (contextualClosure != null)
1185+
{
1186+
return contextualClosure();
1187+
}
1188+
11771189
try
11781190
{
1191+
// 我们不进行CanMake检查以避免一次hash
11791192
return Make(makeServiceBindData.GetContextual(service));
11801193
}
11811194
catch (Exception)
@@ -1198,6 +1211,12 @@ protected virtual object ResloveAttrClass(Bindable makeServiceBindData, string s
11981211
/// <returns>解决结果</returns>
11991212
protected virtual object ResolvePrimitive(Bindable makeServiceBindData, string service, ParameterInfo baseParam)
12001213
{
1214+
var contextualClosure = makeServiceBindData.GetContextualClosure(service);
1215+
if (contextualClosure != null)
1216+
{
1217+
return contextualClosure();
1218+
}
1219+
12011220
service = makeServiceBindData.GetContextual(service);
12021221
if (CanMake(service))
12031222
{
@@ -1227,6 +1246,12 @@ protected virtual object ResolvePrimitive(Bindable makeServiceBindData, string s
12271246
/// <returns>解决结果</returns>
12281247
protected virtual object ResloveClass(Bindable makeServiceBindData, string service, ParameterInfo baseParam)
12291248
{
1249+
var contextualClosure = makeServiceBindData.GetContextualClosure(service);
1250+
if (contextualClosure != null)
1251+
{
1252+
return contextualClosure();
1253+
}
1254+
12301255
try
12311256
{
12321257
return Make(makeServiceBindData.GetContextual(service));

src/CatLib.Core/Support/Container/GivenData.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
* Document: http://catlib.io/
1010
*/
1111

12+
using System;
13+
1214
namespace CatLib
1315
{
1416
/// <summary>
@@ -74,5 +76,17 @@ public TReturn Given<T>()
7476
{
7577
return Given(container.Type2Service(typeof(T)));
7678
}
79+
80+
/// <summary>
81+
/// 给与什么服务
82+
/// </summary>
83+
/// <param name="closure">给与的服务生成闭包</param>
84+
/// <returns>服务绑定数据</returns>
85+
public TReturn Given(Func<object> closure)
86+
{
87+
Guard.Requires<ArgumentNullException>(closure != null);
88+
bindable.AddContextual(needs, closure);
89+
return bindable as TReturn;
90+
}
7791
}
7892
}

src/CatLib.Core/Support/Container/IGivenData.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
* Document: http://catlib.io/
1010
*/
1111

12+
using System;
13+
1214
namespace CatLib
1315
{
1416
/// <summary>
@@ -29,5 +31,12 @@ public interface IGivenData<TReturn>
2931
/// <typeparam name="T">给与的服务名或别名</typeparam>
3032
/// <returns>服务绑定数据</returns>
3133
TReturn Given<T>();
34+
35+
/// <summary>
36+
/// 给与什么服务
37+
/// </summary>
38+
/// <param name="closure">给定的服务</param>
39+
/// <returns>服务绑定数据</returns>
40+
TReturn Given(Func<object> closure);
3241
}
3342
}

0 commit comments

Comments
 (0)