diff --git a/README.md b/README.md index ad3101c..40a842c 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ **使用Nuget安装** ```PM -Install-Package CatLib.Core -Version 1.2.12 +Install-Package CatLib.Core -Version 1.3.0 ``` **直接下载发布版本** diff --git a/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj b/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj index 8922f1d..1a3c472 100644 --- a/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj +++ b/src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj @@ -69,6 +69,7 @@ + @@ -97,6 +98,7 @@ + diff --git a/src/CatLib.Core.Tests/CatLib.Core.Tests.csproj b/src/CatLib.Core.Tests/CatLib.Core.Tests.csproj index 51cf865..84778c3 100644 --- a/src/CatLib.Core.Tests/CatLib.Core.Tests.csproj +++ b/src/CatLib.Core.Tests/CatLib.Core.Tests.csproj @@ -52,7 +52,9 @@ + + diff --git a/src/CatLib.Core.Tests/CatLib/ApplicationTests.cs b/src/CatLib.Core.Tests/CatLib/ApplicationTests.cs index fb1595e..b8a5ce7 100644 --- a/src/CatLib.Core.Tests/CatLib/ApplicationTests.cs +++ b/src/CatLib.Core.Tests/CatLib/ApplicationTests.cs @@ -10,6 +10,7 @@ */ using System; +using System.Collections; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace CatLib.Tests @@ -63,8 +64,32 @@ public void Register() } } + public class TestYieldProvider : ServiceProvider + { + public bool IsDone; + public override IEnumerator CoroutineInit() + { + IsDone = true; + yield return 1; + yield return 2; + yield return base.CoroutineInit(); + } + } + [TestMethod] - [ExpectedException(typeof(RuntimeException))] + public void TestYieldProviderTest() + { + var app = new Application(); + app.Bootstrap(); + var test = new TestYieldProvider(); + app.Register(test); + app.Init(); + + Assert.AreEqual(true, test.IsDone); + } + + [TestMethod] + [ExpectedException(typeof(CodeStandardException))] public void RepeatInitTest() { var app = MakeApplication(); @@ -171,12 +196,12 @@ public void TestStopRegisterProvider() } [TestMethod] - [ExpectedException(typeof(RuntimeException))] + [ExpectedException(typeof(CodeStandardException))] public void TestInitingRegisterProvider() { var application = Application.New(); application.Register(new StopProvider()); - application.On(ApplicationEvents.OnIniting, (b) => + application.On(ApplicationEvents.OnProviderInit, (b) => { application.Register(new TestServiceProvider()); }); @@ -185,7 +210,7 @@ public void TestInitingRegisterProvider() } [TestMethod] - [ExpectedException(typeof(RuntimeException))] + [ExpectedException(typeof(CodeStandardException))] public void TestTerminateRegisterProvider() { var application = Application.New(); @@ -263,15 +288,15 @@ public void GetCurrentProcess() [TestMethod] public void TestDebugLevel() { - App.DebugLevel = DebugLevels.Dev; - Assert.AreEqual(DebugLevels.Dev, App.DebugLevel); + App.DebugLevel = DebugLevels.Development; + Assert.AreEqual(DebugLevels.Development, App.DebugLevel); } /// /// 重复的引导测试 /// [TestMethod] - [ExpectedException(typeof(RuntimeException))] + [ExpectedException(typeof(CodeStandardException))] public void RepeatBootstrap() { var app = new Application(); @@ -441,6 +466,22 @@ public void TestIsMainThread() Assert.AreEqual(true, app.IsMainThread); } + public class TestRegisterProcessMakeServiceProvider : ServiceProvider + { + public override void Register() + { + App.Make(); + } + } + + [TestMethod] + [ExpectedException(typeof(CodeStandardException))] + public void TestRegisterProcessMake() + { + var app = MakeApplication(); + app.Register(new TestRegisterProcessMakeServiceProvider()); + } + private Application MakeApplication() { var app = new Application(); diff --git a/src/CatLib.Core.Tests/CatLib/FacaedTests.cs b/src/CatLib.Core.Tests/CatLib/FacaedTests.cs index 718b56a..8c7fd42 100644 --- a/src/CatLib.Core.Tests/CatLib/FacaedTests.cs +++ b/src/CatLib.Core.Tests/CatLib/FacaedTests.cs @@ -190,8 +190,6 @@ public void TestNotBind() public void TestStructBindAndRebound() { var app = new Application(); - Assert.AreEqual(0, Facade.Instance); - Assert.AreEqual(0, Facade.Instance); // double check var makeCount = 0; var binder = app.Bind(() => { @@ -200,7 +198,7 @@ public void TestStructBindAndRebound() }); Assert.AreEqual(100, Facade.Instance); Assert.AreEqual(100, Facade.Instance); // double check - Assert.AreEqual(3, makeCount); // 这里为3是因为最开始的facade触发已经引发了解决事件 + Assert.AreEqual(2, makeCount); binder.Unbind(); Assert.AreEqual(0, Facade.Instance); Assert.AreEqual(0, Facade.Instance); // double check @@ -211,7 +209,7 @@ public void TestStructBindAndRebound() }); Assert.AreEqual(200, Facade.Instance); Assert.AreEqual(200, Facade.Instance); // double check - Assert.AreEqual(6, makeCount); + Assert.AreEqual(5, makeCount); // 其中多出的一个计数是门面的watch导致的。 } [TestMethod] diff --git a/src/CatLib.Core.Tests/Properties/AssemblyInfo.cs b/src/CatLib.Core.Tests/Properties/AssemblyInfo.cs index e32692f..ad53280 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.2.0.0")] -[assembly: AssemblyFileVersion("1.2.12.0")] +[assembly: AssemblyVersion("1.3.0.0")] +[assembly: AssemblyFileVersion("1.3.0.0")] diff --git a/src/CatLib.Core.Tests/Support/Container/BindDataTests.cs b/src/CatLib.Core.Tests/Support/Container/BindDataTests.cs index c38e831..805835c 100644 --- a/src/CatLib.Core.Tests/Support/Container/BindDataTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/BindDataTests.cs @@ -209,6 +209,21 @@ public void TestAddOnResolvingWithExtend() Assert.AreEqual("hello world", data); } + [TestMethod] + public void TestAddOnResolvingWithExtendNoneInstance() + { + var container = new Container(); + var bindData = new BindData(container, "CanAddOnResolving", (app, param) => "hello world", false); + var call = false; + bindData.OnResolving(() => + { + call = true; + }); + var data = bindData.TriggerResolving("hello world"); + Assert.AreEqual("hello world", data); + Assert.AreEqual(true, call); + } + /// /// 是否能追加到解决事件 /// diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerHelperTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerHelperTests.cs index 918c26e..c3f2232 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerHelperTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerHelperTests.cs @@ -265,8 +265,8 @@ public void TestWatch() container.Instance(container); var cls = new TestWatchCLass(); - container.Watch(cls, "OnChange"); container.Instance(100); + container.Watch(cls, "OnChange"); container.Instance(200); Assert.AreEqual(200, cls.value); @@ -280,12 +280,12 @@ public void TestWatchLambda() container.Instance(container); var isCall = false; + container.Instance(new TestData(100)); container.Watch((val) => { isCall = true; Assert.AreEqual(200, val.getValue()); }); - container.Instance(new TestData(100)); container.Instance(new TestData(200)); Assert.AreEqual(true, isCall); @@ -299,11 +299,11 @@ public void TestWatchLambdaNoParam() container.Instance(container); var isCall = false; + container.Instance(100); container.Watch(() => { isCall = true; }); - container.Instance(100); container.Instance(200); Assert.AreEqual(true, isCall); @@ -344,6 +344,16 @@ public void TestReleaseWithObject() Assert.AreEqual(998, data[1]); } + [TestMethod] + public void TestSetAlias() + { + var container = new Container(); + container.Instance("abc"); + container.Alias(); + + Assert.AreEqual("abc", container.Make()); + } + /// /// 生成容器 /// @@ -352,7 +362,7 @@ private Container MakeContainer() { var container = new Container(); container.Instance("ContainerHelperTests", this); - container.Instance(container.Type2Service(typeof(ContainerHelperTests)), this); + container.Alias(container.Type2Service(typeof(ContainerHelperTests)), "ContainerHelperTests"); return container; } } diff --git a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs index cba9cbe..e8a11f4 100644 --- a/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/ContainerTests.cs @@ -700,7 +700,8 @@ public void CheckIllegalCallMethod() public void TestContainerCallWithNullParams() { var container = MakeContainer(); - container.Instance("@num", 777); + container.Instance("num", 777); + container.Alias("$num", "num"); var result = container.Call(this, "TestContainerCall", null); Assert.AreEqual(777, result); } @@ -709,7 +710,7 @@ public void TestContainerCallWithNullParams() public void TestContainerCallWithErrorParams() { var container = MakeContainer(); - container.Instance("@num", "helloworld"); + container.Singleton("num", (_, __) => "helloworld").Alias("$num"); ExceptionAssert.Throws(() => { container.Call(this, "TestContainerCall", null); @@ -849,7 +850,7 @@ public void MakeNoClassAttrInject() { var container = MakeContainer(); container.Bind(); - container.Bind("@Time", (c, p) => 100, false); + container.Bind("Time", (c, p) => 100, false).Alias("$Time"); var result = container.Make(); Assert.AreEqual(100, result.Time); @@ -906,7 +907,7 @@ public void MakeNotClassConstructor() var container = MakeContainer(); container.Bind(); container.Bind(); - container.Instance("@i", 77); + container.Singleton("i", (_,__) => 77).Alias("$i"); var result = container.Make(); Assert.AreEqual(77, result.I); Assert.AreNotEqual(null, result.Dependency); @@ -1888,7 +1889,8 @@ public void TestBaseStructChangeInvalid() public void TestFormatException() { var container = new Container(); - container.Instance("@num", 10); + container.Instance("num", 10); + container.Alias("$num", "num"); Assert.AreEqual(10, container.Call(this, "TestContainerCall", new ContainerTest())); } @@ -2061,11 +2063,13 @@ public void TestResloveAttrClassSpeculationServiceFunc() { var container = new Container(); container.Bind(); - container.Instance("@ex", new UnresolvableException()); - container.Instance("@rex", new UnresolvableException()); + container.Instance("ex", new UnresolvableException()); + container.Alias("$ex", "ex"); + container.Instance("rex", new UnresolvableException()); + container.Alias("$rex", "rex"); var cls = container.Make(); - Assert.AreSame(container.Make("@ex"), cls.ex); + Assert.AreSame(container.Make("$ex"), cls.ex); } [TestMethod] @@ -2073,7 +2077,8 @@ public void TestResloveAttrClassSpeculationServiceAttrs() { var container = new Container(); container.Bind(); - container.Instance("@ex", new UnresolvableException()); + container.Instance("ex", new UnresolvableException()); + container.Alias("$ex", "ex"); ExceptionAssert.Throws(() => { @@ -2195,6 +2200,58 @@ public void TestCallInjectCurrent() Assert.AreEqual(true, isCall); } + [TestMethod] + [ExpectedException(typeof(CodeStandardException))] + public void TestNotSupportBindChars() + { + var container = new Container(); + container.Bind("@", (_, __) => 123); + } + + [TestMethod] + [ExpectedException(typeof(CodeStandardException))] + public void TestNotSupportInstanceChars() + { + var container = new Container(); + container.Instance("char:char", 123); + } + + [TestMethod] + [ExpectedException(typeof(CodeStandardException))] + public void TestRegisterSameObjectInstance() + { + var container = new Container(); + var data = new object(); + container.Instance("char1", data); + container.Instance("char2", data); + } + + [TestMethod] + public void TestRegisterNotSameObjectInstance() + { + var container = new Container(); + container.Instance("char1", 1); + container.Instance("char2", 2); + } + + [TestMethod] + [ExpectedException(typeof(CodeStandardException))] + public void TestReboundNotExistsService() + { + var container = new Container(); + container.OnRebound("123", (_) => + { + + }); + } + + [TestMethod] + public void TestNullUnbind() + { + var container = new Container(); + container.Unbind("Not Exists"); + } + /// /// 测试基础容器调用 /// @@ -2210,13 +2267,14 @@ public void TestOnRebound() { var container = new Container(); var callRebound = false; + + var temp = container.Bind("TestService", (c, p) => 100); container.OnRebound("TestService", (instance) => { Assert.AreEqual(300, instance); callRebound = true; }); - - container.Bind("TestService", (c, p) => 100).Unbind(); + temp.Unbind(); var bind = container.Bind("TestService", (c, p) => 200); container.Make("TestService"); bind.Unbind(); @@ -2230,13 +2288,13 @@ public void TestOnReboundWithInstance() { var container = new Container(); var callRebound = false; + + container.Instance("TestService", 100); container.OnRebound("TestService", (instance) => { Assert.AreEqual(300, instance); callRebound = true; }); - - container.Instance("TestService", 100); container.Instance("TestService", 300); Assert.AreEqual(true, callRebound); @@ -2261,9 +2319,9 @@ public void TestWatch() var container = new Container(); container.Instance(container); - var cls = new TestWatchCLass(); - container.Watch("WatchService", cls, "OnChange"); + var cls = new TestWatchCLass(); container.Instance("WatchService", 100); + container.Watch("WatchService", cls, "OnChange"); container.Instance("WatchService", 200); Assert.AreEqual(200, cls.value); @@ -2292,9 +2350,8 @@ public void TestOccupiedKeyInstance() var container = new Container(); container.Instance(null); var cls = new TestWatchCLass(); - container.Watch("WatchService", cls, "OnChange"); container.Instance("WatchService", 100); - + container.Watch("WatchService", cls, "OnChange"); var isThrow = false; try { @@ -2366,6 +2423,110 @@ public void TestFlushAndInstance() Assert.AreEqual(true, isError); } + + public class TestFlushOrderDependencyClass + { + + } + + public class TestFlushOrderClass + { + public TestFlushOrderClass(TestFlushOrderDependencyClass cls) + { + + } + } + + [TestMethod] + public void TestFlushOrder() + { + var container = new Container(); + container.Instance(container); + + var list = new List(); + + container.OnRelease((_) => + { + list.Add(_); + }); + + container.Singleton(); + container.Singleton(); + + container.Make(); + + container.Flush(); + + Assert.AreEqual(3, list.Count); + Assert.AreEqual(typeof(TestFlushOrderClass), list[0].GetType()); + Assert.AreEqual(typeof(TestFlushOrderDependencyClass), list[1].GetType()); + Assert.AreEqual(typeof(Container), list[2].GetType()); + } + + [TestMethod] + public void TestRebuildAndFlush() + { + var container = new Application(); + var list = new List(); + + container.Singleton(); + container.Singleton(); + + container.Make(); + var temp = Facade.Instance; + container.Release(); + + container.OnRelease((_) => + { + if(typeof(TestFlushOrderDependencyClass) == _.GetType() + || typeof(Application) == _.GetType() + || typeof(TestFlushOrderClass) == _.GetType()) + list.Add(_); + }); + container.Instance(new TestFlushOrderDependencyClass()); + + container.Flush(); + + Assert.AreEqual(3, list.Count); + Assert.AreEqual(typeof(TestFlushOrderClass), list[0].GetType()); + Assert.AreEqual(typeof(TestFlushOrderDependencyClass), list[1].GetType()); + Assert.AreEqual(typeof(Application), list[2].GetType()); + } + + [TestMethod] + public void TestRebuildAndFlushNotWatch() + { + var container = new Application(); + var list = new List(); + + container.Singleton(); + container.Singleton(); + + container.Make(); + container.Release(); + + container.OnRelease((_) => + { + if (typeof(TestFlushOrderDependencyClass) == _.GetType() + || typeof(Application) == _.GetType() + || typeof(TestFlushOrderClass) == _.GetType()) + list.Add(_); + }); + container.Instance(new TestFlushOrderDependencyClass()); + + container.Flush(); + + Assert.AreEqual(3, list.Count); + Assert.AreEqual(typeof(TestFlushOrderDependencyClass), list[0].GetType()); + Assert.AreEqual(typeof(TestFlushOrderClass), list[1].GetType()); + Assert.AreEqual(typeof(Application), list[2].GetType()); + } + + [TestMethod] + public void TestCannotWatch() + { + + } #endregion /// diff --git a/src/CatLib.Core.Tests/Support/Container/MethodContainerTests.cs b/src/CatLib.Core.Tests/Support/Container/MethodContainerTests.cs index efe424f..257760f 100644 --- a/src/CatLib.Core.Tests/Support/Container/MethodContainerTests.cs +++ b/src/CatLib.Core.Tests/Support/Container/MethodContainerTests.cs @@ -141,14 +141,17 @@ public void TestUnbindWithObject() public void TestContainerMethodContextual() { new Application(); - App.Instance("@input", 1000); - App.Instance("@input2", 2000); + + App.Instance("input", 1000); + App.Alias("$input", "input"); + App.Instance("input2", 2000); + App.Alias("$input2", "input2"); var cls = new TestContainerClass(); - App.BindMethod("Helloworld.Func1", cls).Needs("@input").Given("@input2"); + App.BindMethod("Helloworld.Func1", cls).Needs("$input").Given("$input2"); App.BindMethod("Helloworld.Func2", cls) - .Needs("@input").Given("@input2") - .Needs("@input2").Given("@input"); ; + .Needs("$input").Given("$input2") + .Needs("$input2").Given("$input"); ; Assert.AreEqual(2000, App.Invoke("Helloworld.Func1")); Assert.AreEqual((float)1000, App.Invoke("Helloworld.Func2")); diff --git a/src/CatLib.Core.Tests/Support/Stream/CombineStreamTests.cs b/src/CatLib.Core.Tests/Support/Stream/CombineStreamTests.cs new file mode 100644 index 0000000..70f946f --- /dev/null +++ b/src/CatLib.Core.Tests/Support/Stream/CombineStreamTests.cs @@ -0,0 +1,242 @@ +/* + * 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; +using System; +using System.IO; + +namespace CatLib +{ + [TestClass] + public class CombineStreamTests + { + [TestMethod] + public void TestCombineStream() + { + var mem1 = "hello".ToStream(); + var mem2 = "world".ToStream(); + + var stream = new CombineStream(mem1, mem2); + Assert.AreEqual("helloworld", stream.ToText()); + } + + [TestMethod] + public void TestCombineStream2() + { + var mem1 = "hello".ToStream(); + var mem2 = "world".ToStream(); + var stream = new CombineStream(mem1, mem2); + + var buffer = new byte[5]; + Assert.AreEqual(5, stream.Read(buffer, 0, 5)); + Assert.AreEqual("hello", Util.Encoding.GetString(buffer)); + Assert.AreEqual(5, stream.Read(buffer, 0, 5)); + Assert.AreEqual("world", Util.Encoding.GetString(buffer)); + } + + [TestMethod] + public void TestCombineSeek() + { + var mem1 = "hello".ToStream(); + var mem2 = "world".ToStream(); + var stream = new CombineStream(mem1, mem2); + + var buffer = new byte[5]; + Assert.AreEqual(5, stream.Read(buffer, 0, 5)); + Assert.AreEqual("hello", Util.Encoding.GetString(buffer)); + Assert.AreEqual(5, stream.Read(buffer, 0, 5)); + Assert.AreEqual("world", Util.Encoding.GetString(buffer)); + + stream.Seek(5, SeekOrigin.Begin); + Assert.AreEqual(5, stream.Read(buffer, 0, 5)); + Assert.AreEqual("world", Util.Encoding.GetString(buffer)); + + stream.Seek(4, SeekOrigin.Begin); + Assert.AreEqual(5, stream.Read(buffer, 0, 5)); + Assert.AreEqual("oworl", Util.Encoding.GetString(buffer)); + stream.Seek(6, SeekOrigin.Begin); + Assert.AreEqual(4, stream.Read(buffer, 0, 5)); + Assert.AreEqual("orld", Util.Encoding.GetString(buffer, 0, 4)); + stream.Seek(10, SeekOrigin.Begin); + Assert.AreEqual(0, stream.Read(buffer, 0, 5)); + Assert.AreEqual(0, stream.Read(buffer, 0, 5)); + } + + [TestMethod] + public void TestCombineSeek2() + { + var mem1 = "hello".ToStream(); + var mem2 = "world".ToStream(); + var stream = new CombineStream(mem1, mem2); + + var buffer = new byte[5]; + Assert.AreEqual(5, stream.Read(buffer, 0, 5)); + Assert.AreEqual("hello", Util.Encoding.GetString(buffer)); + stream.Seek(2, SeekOrigin.Current); + Assert.AreEqual(3, stream.Read(buffer, 0, 5)); + Assert.AreEqual("rld", Util.Encoding.GetString(buffer, 0, 3)); + stream.Seek(-3, SeekOrigin.End); + Assert.AreEqual(3, stream.Read(buffer, 0, 5)); + Assert.AreEqual("rld", Util.Encoding.GetString(buffer, 0, 3)); + } + + [TestMethod] + public void TestSetPosition() + { + var mem1 = "hello".ToStream(); + var mem2 = "world".ToStream(); + var stream = new CombineStream(mem1, mem2); + + var buffer = new byte[5]; + Assert.AreEqual(5, stream.Read(buffer, 0, 5)); + Assert.AreEqual("hello", Util.Encoding.GetString(buffer)); + + Assert.AreEqual(5, stream.Position); + stream.Position = 0; + Assert.AreEqual(5, stream.Read(buffer, 0, 5)); + Assert.AreEqual("hello", Util.Encoding.GetString(buffer)); + } + + [TestMethod] + public void TestGetContstValue() + { + var mem1 = "hello".ToStream(); + var mem2 = "world".ToStream(); + var stream = new CombineStream(mem1, mem2); + + Assert.AreEqual(false, stream.CanWrite); + Assert.AreEqual(true, stream.CanSeek); + Assert.AreEqual(true, stream.CanRead); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void TestSeekOutOfRange() + { + var mem1 = "hello".ToStream(); + var mem2 = "world".ToStream(); + var stream = new CombineStream(mem1, mem2); + stream.Seek(11, SeekOrigin.Begin); + } + + public class CannotSeekStream : Stream + { + public override bool CanRead { get; } + public override bool CanSeek => false; + + public override bool CanWrite { get; } + + public override long Position { get; set; } + + public override long Length { get; } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotImplementedException(); + } + + public override void Flush() + { + throw new NotImplementedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotImplementedException(); + } + + public override void SetLength(long value) + { + throw new NotImplementedException(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + throw new NotImplementedException(); + } + } + + [TestMethod] + public void TestCannotSeekStream() + { + var stream = new CombineStream("hello".ToStream(), new CannotSeekStream()); + Assert.AreEqual(false, stream.CanSeek); + } + + [TestMethod] + [ExpectedException(typeof(NotSupportedException))] + public void TestCannotSeekStreamSetPosition() + { + var stream = new CombineStream("hello".ToStream(), new CannotSeekStream()); + stream.Seek(0, SeekOrigin.Begin); + } + + [TestMethod] + [ExpectedException(typeof(NotSupportedException))] + public void TestUnknowSeek() + { + var mem1 = "hello".ToStream(); + var mem2 = "world".ToStream(); + var stream = new CombineStream(mem1, mem2); + stream.Seek(11, (SeekOrigin)100); + } + + [TestMethod] + public void TestDispose() + { + var mem1 = "hello".ToStream(); + var mem2 = "world".ToStream(); + + Assert.AreEqual(true, mem1.CanWrite); + Assert.AreEqual(true, mem2.CanWrite); + + using (var stream = new CombineStream(mem1, mem2, true)) + { + } + + Assert.AreEqual(false, mem1.CanWrite); + Assert.AreEqual(false, mem2.CanWrite); + } + + [TestMethod] + [ExpectedException(typeof(NotSupportedException))] + public void TestWrite() + { + var mem1 = "hello".ToStream(); + var mem2 = "world".ToStream(); + var stream = new CombineStream(mem1, mem2); + + stream.Write(new byte[5], 0, 1); + } + + [TestMethod] + [ExpectedException(typeof(NotSupportedException))] + public void TestSetLength() + { + var mem1 = "hello".ToStream(); + var mem2 = "world".ToStream(); + var stream = new CombineStream(mem1, mem2); + + stream.SetLength(10); + } + + [TestMethod] + [ExpectedException(typeof(NotSupportedException))] + public void TestFlush() + { + var mem1 = "hello".ToStream(); + var mem2 = "world".ToStream(); + var stream = new CombineStream(mem1, mem2); + + stream.Flush(); + } + } +} diff --git a/src/CatLib.Core.Tests/Support/Stream/SegmentStreamTests.cs b/src/CatLib.Core.Tests/Support/Stream/SegmentStreamTests.cs new file mode 100644 index 0000000..4b56e65 --- /dev/null +++ b/src/CatLib.Core.Tests/Support/Stream/SegmentStreamTests.cs @@ -0,0 +1,188 @@ +/* + * 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.IO; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace CatLib.Core.Tests.Support.Stream +{ + [TestClass] + public class SegmentStreamTests + { + [TestMethod] + public void TestRead() + { + var baseStream = "hello world , my name is miaomiao".ToStream(); + var segmentStream = new SegmentStream(baseStream, 11); + Assert.AreEqual("hello world", segmentStream.ToText()); + } + + [TestMethod] + public void TestReadMiddle() + { + var baseStream = "hello world , my name is miaomiao".ToStream(); + baseStream.Seek(14, SeekOrigin.Begin); + var segmentStream = new SegmentStream(baseStream, 10); + + Assert.AreEqual("my name is", segmentStream.ToText()); + } + + [TestMethod] + public void TestReadEnd() + { + var baseStream = "hello world , my name is miaomiao".ToStream(); + baseStream.Seek(14, SeekOrigin.Begin); + var segmentStream = new SegmentStream(baseStream); + + Assert.AreEqual("my name is miaomiao", segmentStream.ToText()); + } + + + [TestMethod] + public void TestSeekEnd() + { + var baseStream = "hello world , my name is miaomiao".ToStream(); + var segmentStream = new SegmentStream(baseStream, 11); + segmentStream.Seek(-5, SeekOrigin.End); + + Assert.AreEqual("world", segmentStream.ToText()); + } + + [TestMethod] + public void TestSeekCurrent() + { + var baseStream = "hello world , my name is miaomiao".ToStream(); + baseStream.Seek(2, SeekOrigin.Begin); + var segmentStream = new SegmentStream(baseStream, 9); + segmentStream.Seek(4, SeekOrigin.Current); + Assert.AreEqual("world", segmentStream.ToText()); + } + + [TestMethod] + public void TestSeekBegin() + { + var baseStream = "hello world , my name is miaomiao".ToStream(); + var segmentStream = new SegmentStream(baseStream, 11); + segmentStream.ToText(null, false); + segmentStream.Seek(0, SeekOrigin.Begin); + Assert.AreEqual("hello world", segmentStream.ToText()); + } + + [TestMethod] + public void TestGetLength() + { + var baseStream = "hello world , my name is miaomiao".ToStream(); + var segmentStream = new SegmentStream(baseStream, 11); + Assert.AreEqual(11, segmentStream.Length); + } + + [TestMethod] + public void TestGetPosition() + { + var baseStream = "hello world , my name is miaomiao".ToStream(); + baseStream.Seek(2, SeekOrigin.Begin); + var segmentStream = new SegmentStream(baseStream, 9) {Position = 4}; + Assert.AreEqual(4, segmentStream.Position); + } + + [TestMethod] + public void TestReadBuffer() + { + var baseStream = "hello world , my name is miaomiao".ToStream(); + var segmentStream = new SegmentStream(baseStream, 11); + var buffer = new byte[255]; + Assert.AreEqual(11, segmentStream.Read(buffer, 0, 255)); + Assert.AreEqual("hello world", CatLib.Util.Encoding.GetString(buffer, 0, 11)); + } + + [TestMethod] + public void TestReadBufferEnd() + { + var baseStream = "hello world , my name is miaomiao".ToStream(); + var segmentStream = new SegmentStream(baseStream, 11); + var buffer = new byte[255]; + Assert.AreEqual(11, segmentStream.Read(buffer, 0, 255)); + Assert.AreEqual("hello world", CatLib.Util.Encoding.GetString(buffer, 0, 11)); + Assert.AreEqual(0, segmentStream.Read(buffer, 0, 255)); + } + + [TestMethod] + public void TestReadBufferMin() + { + var baseStream = "hello world , my name is miaomiao".ToStream(); + var segmentStream = new SegmentStream(baseStream, 11); + var buffer = new byte[5]; + Assert.AreEqual(5, segmentStream.Read(buffer, 0, 5)); + Assert.AreEqual("hello", CatLib.Util.Encoding.GetString(buffer, 0, 5)); + } + + [TestMethod] + [ExpectedException(typeof(NotSupportedException))] + public void TestSetLength() + { + var baseStream = "hello world , my name is miaomiao".ToStream(); + var segmentStream = new SegmentStream(baseStream, 11); + segmentStream.SetLength(100); + } + + [TestMethod] + [ExpectedException(typeof(NotSupportedException))] + public void TestWrite() + { + var baseStream = "hello world , my name is miaomiao".ToStream(); + var segmentStream = new SegmentStream(baseStream, 11); + var buffer = CatLib.Util.Encoding.GetBytes("hello world"); + + segmentStream.Write(buffer, 0, buffer.Length); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void TestNotSupportSeekOrigin() + { + var baseStream = "hello world , my name is miaomiao".ToStream(); + var segmentStream = new SegmentStream(baseStream, 11); + segmentStream.Seek(0, (SeekOrigin) 100); + } + + [TestMethod] + public void TestSeekEndToRead() + { + var baseStream = "hello world , my name is miaomiao".ToStream(); + var segmentStream = new SegmentStream(baseStream, 11); + segmentStream.Seek(100, SeekOrigin.End); + Assert.AreEqual(string.Empty, segmentStream.ToText()); + } + + [TestMethod] + public void TestSeekSmallThenStart() + { + var baseStream = "hello world , my name is miaomiao".ToStream(); + var segmentStream = new SegmentStream(baseStream, 11); + segmentStream.Seek(-100, SeekOrigin.Begin); + Assert.AreEqual("hello world", segmentStream.ToText()); + } + + + private class CanNotSeekStream : WrapperStream + { + public override bool CanSeek => false; + } + + [TestMethod] + [ExpectedException(typeof(InvalidOperationException))] + public void TestGivenCanNotSeek() + { + var segmentStream = new SegmentStream(new CanNotSeekStream()); + } + } +} diff --git a/src/CatLib.Core.Tests/Support/Util/ArrTests.cs b/src/CatLib.Core.Tests/Support/Util/ArrTests.cs index a87d5a1..b6e50d3 100644 --- a/src/CatLib.Core.Tests/Support/Util/ArrTests.cs +++ b/src/CatLib.Core.Tests/Support/Util/ArrTests.cs @@ -10,6 +10,7 @@ */ using System; +using System.Collections.Generic; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace CatLib.Tests.Support.Util @@ -33,6 +34,13 @@ public void TestMerge() Assert.AreEqual(3, newArr.Length); } + [TestMethod] + public void TestMergeAllEmpty() + { + var newArr = Arr.Merge(new int[0], new int[0]); + Assert.AreEqual(0, newArr.Length); + } + [TestMethod] public void TestMergeNull() { @@ -374,7 +382,19 @@ public void TestFillException() [TestMethod] public void TestFilter() { - var result = Arr.Filter(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }, (i) => i % 2 == 0); + var result = Arr.Filter(new [] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }, (i) => i % 2 == 0); + Assert.AreEqual(2, result[0]); + Assert.AreEqual(4, result[1]); + Assert.AreEqual(6, result[2]); + Assert.AreEqual(8, result[3]); + Assert.AreEqual(0, result[4]); + Assert.AreEqual(5, result.Length); + } + + [TestMethod] + public void TestFilterIEnumerable() + { + var result = Arr.Filter(new List { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }, (i) => i % 2 == 0); Assert.AreEqual(2, result[0]); Assert.AreEqual(4, result[1]); Assert.AreEqual(6, result[2]); @@ -397,6 +417,24 @@ public void TestMap() Assert.AreEqual(3, data[2]); } + [TestMethod] + public void TestMapIEnumerable() + { + var data = new List + { + 1,2,3 + }; + + var result = Arr.Map(data, (i) => i * 2); + Assert.AreEqual(2, result[0]); + Assert.AreEqual(4, result[1]); + Assert.AreEqual(6, result[2]); + + Assert.AreEqual(1, data[0]); + Assert.AreEqual(2, data[1]); + Assert.AreEqual(3, data[2]); + } + [TestMethod] public void TestPop() { diff --git a/src/CatLib.Core/CatLib.Core.csproj b/src/CatLib.Core/CatLib.Core.csproj index 3f2adb0..141ccc7 100644 --- a/src/CatLib.Core/CatLib.Core.csproj +++ b/src/CatLib.Core/CatLib.Core.csproj @@ -50,6 +50,7 @@ + @@ -80,6 +81,7 @@ + @@ -90,9 +92,12 @@ + + + diff --git a/src/CatLib.Core/CatLib/App.cs b/src/CatLib.Core/CatLib/App.cs index 65add84..eed05e7 100644 --- a/src/CatLib.Core/CatLib/App.cs +++ b/src/CatLib.Core/CatLib/App.cs @@ -37,21 +37,11 @@ public abstract class App /// public static IApplication Handler { - get - { - if (instance == null) - { - return New(); - } - return instance; - } + get => instance ?? New(); set { instance = value; - if (OnNewApplication != null) - { - OnNewApplication.Invoke(instance); - } + OnNewApplication?.Invoke(instance); } } @@ -105,24 +95,12 @@ public static long GetRuntimeId() /// /// 是否是主线程 /// - public static bool IsMainThread - { - get - { - return Handler.IsMainThread; - } - } + public static bool IsMainThread => Handler.IsMainThread; /// /// CatLib版本(遵循semver) /// - public static string Version - { - get - { - return Handler.Version; - } - } + public static string Version => Handler.Version; /// /// 比较CatLib版本(遵循semver) @@ -169,8 +147,8 @@ public static int GetPriority(Type type, string method = null) /// public static DebugLevels DebugLevel { - get { return Handler.DebugLevel; } - set { Handler.DebugLevel = value; } + get => Handler.DebugLevel; + set => Handler.DebugLevel = value; } #endregion @@ -750,6 +728,16 @@ public static bool IsAlias() return Handler.IsAlias(); } + /// + /// 为服务设定一个别名 + /// + /// 别名 + /// 服务名 + public static IContainer Alias() + { + return Handler.Alias(Handler.Type2Service(typeof(TAlias)), Handler.Type2Service(typeof(TService))); + } + /// /// 常规绑定一个服务 /// diff --git a/src/CatLib.Core/CatLib/Application.cs b/src/CatLib.Core/CatLib/Application.cs index c4e14ea..5da6c5b 100644 --- a/src/CatLib.Core/CatLib/Application.cs +++ b/src/CatLib.Core/CatLib/Application.cs @@ -10,6 +10,7 @@ */ using System; +using IEnumerator = System.Collections.IEnumerator; using System.Collections.Generic; using System.Threading; @@ -23,7 +24,7 @@ public class Application : Container, IApplication, IOriginalDispatcher /// /// 版本号 /// - private readonly Version version = new Version("1.2.12"); + private readonly Version version = new Version("1.3.0"); /// /// 框架启动流程 @@ -107,21 +108,14 @@ public enum StartProcess private bool inited; /// - /// 启动流程 + /// 是否正在注册中 /// - private StartProcess process; + private bool registering; /// /// 启动流程 /// - public StartProcess Process - { - get - { - return process; - } - private set { process = value; } - } + public StartProcess Process { get; private set; } /// /// 增量Id @@ -136,13 +130,7 @@ public StartProcess Process /// /// 是否是主线程 /// - public bool IsMainThread - { - get - { - return mainThreadId == Thread.CurrentThread.ManagedThreadId; - } - } + public bool IsMainThread => mainThreadId == Thread.CurrentThread.ManagedThreadId; /// /// 事件系统 @@ -152,13 +140,7 @@ public bool IsMainThread /// /// 事件系统 /// - public IDispatcher Dispatcher - { - get - { - return dispatcher ?? (dispatcher = this.Make()); - } - } + public IDispatcher Dispatcher => dispatcher ?? (dispatcher = this.Make()); /// /// 构建一个CatLib实例 @@ -209,7 +191,7 @@ public virtual void Bootstrap(params IBootstrap[] bootstraps) if (bootstrapped || Process != StartProcess.Construct) { - throw new RuntimeException("Cannot repeatedly trigger the Bootstrap()"); + throw new CodeStandardException($"Cannot repeatedly trigger the {nameof(Bootstrap)}()"); } Process = StartProcess.Bootstrap; @@ -220,7 +202,10 @@ public virtual void Bootstrap(params IBootstrap[] bootstraps) foreach (var bootstrap in bootstraps) { - sorting.Add(bootstrap, GetPriority(bootstrap.GetType(), "Bootstrap")); + if (bootstrap != null) + { + sorting.Add(bootstrap, GetPriority(bootstrap.GetType(), nameof(IBootstrap.Bootstrap))); + } } foreach (var bootstrap in sorting) @@ -240,17 +225,25 @@ public virtual void Bootstrap(params IBootstrap[] bootstraps) /// /// 初始化 /// - /// 没有调用Bootstrap(...)就尝试初始化时触发 public virtual void Init() + { + StartCoroutine(CoroutineInit()); + } + + /// + /// 初始化 + /// + /// 没有调用Bootstrap(...)就尝试初始化时触发 + protected IEnumerator CoroutineInit() { if (!bootstrapped) { - throw new RuntimeException("You must call Bootstrap() first."); + throw new CodeStandardException($"You must call {nameof(Bootstrap)}() first."); } if (inited || Process != StartProcess.Bootstraped) { - throw new RuntimeException("Cannot repeatedly trigger the Init()"); + throw new CodeStandardException($"Cannot repeatedly trigger the {nameof(Init)}()"); } Process = StartProcess.Init; @@ -259,8 +252,7 @@ public virtual void Init() foreach (var provider in serviceProviders) { - Trigger(ApplicationEvents.OnIniting, provider); - provider.Init(); + yield return InitProvider(provider); } inited = true; @@ -277,41 +269,75 @@ public virtual void Init() /// 注册服务提供者 /// 服务提供者被重复注册时触发 public virtual void Register(IServiceProvider provider) + { + StartCoroutine(CoroutineRegister(provider)); + } + + /// + /// 注册服务提供者 + /// + /// 注册服务提供者 + /// 服务提供者被重复注册时触发 + protected IEnumerator CoroutineRegister(IServiceProvider provider) { Guard.Requires(provider != null); if (IsRegisted(provider)) { - throw new RuntimeException("Provider [" + provider.GetType() + "] is already register."); + throw new RuntimeException($"Provider [{provider.GetType()}] is already register."); } - if(Process == StartProcess.Initing) + if (Process == StartProcess.Initing) { - throw new RuntimeException("Unable to add service provider during StartProcess.Initing"); + throw new CodeStandardException($"Unable to add service provider during {nameof(StartProcess.Initing)}"); } - if(Process > StartProcess.Running) + if (Process > StartProcess.Running) { - throw new RuntimeException("Unable to Terminate in-process registration service provider"); + throw new CodeStandardException($"Unable to {nameof(Terminate)} in-process registration service provider"); } var allow = TriggerHalt(ApplicationEvents.OnRegisterProvider, provider) == null; if (!allow) { - return; + yield break; } - provider.Register(); - serviceProviders.Add(provider, GetPriority(provider.GetType(), "Init")); + try + { + registering = true; + provider.Register(); + } + finally + { + registering = false; + } + serviceProviders.Add(provider, GetPriority(provider.GetType(), nameof(IServiceProvider.Init))); serviceProviderTypes.Add(GetProviderBaseType(provider)); if (inited) { - Trigger(ApplicationEvents.OnIniting, provider); - provider.Init(); + yield return InitProvider(provider); } } + /// + /// 初始化服务提供者 + /// + /// 服务提供者 + private IEnumerator InitProvider(IServiceProvider provider) + { + Trigger(ApplicationEvents.OnProviderInit, provider); + + provider.Init(); + if (provider is ICoroutineInit coroutine) + { + yield return coroutine.CoroutineInit(); + } + + Trigger(ApplicationEvents.OnProviderInited, provider); + } + /// /// 服务提供者是否已经注册过 /// @@ -348,14 +374,8 @@ public int GetPriority(Type type, string method = null) /// public DebugLevels DebugLevel { - get - { - return (DebugLevels)Make(Type2Service(typeof(DebugLevels))); - } - set - { - Instance(Type2Service(typeof(DebugLevels)), value); - } + get => (DebugLevels)Make(Type2Service(typeof(DebugLevels))); + set => Instance(Type2Service(typeof(DebugLevels)), value); } /// @@ -424,13 +444,7 @@ public void Off(object target) /// CatLib版本(遵循semver) /// [ExcludeFromCodeCoverage] - public string Version - { - get - { - return version.ToString(); - } - } + public string Version => version.ToString(); /// /// 比较CatLib版本(遵循semver) @@ -445,7 +459,7 @@ public string Version [ExcludeFromCodeCoverage] public int Compare(int major, int minor, int revised) { - return Compare(string.Format("{0}.{1}.{2}", major, minor, revised)); + return Compare($"{major}.{minor}.{revised}"); } /// @@ -462,10 +476,24 @@ public int Compare(string version) return this.version.Compare(version); } + /// + /// 验证构建状态 + /// + /// 函数名 + protected override void GuardConstruct(string method) + { + if (registering) + { + throw new CodeStandardException( + $"It is not allowed to make services or dependency injection in the registration process, method:{method}"); + } + base.GuardConstruct(method); + } + /// /// 注册核心别名 /// - protected virtual void RegisterCoreAlias() + private void RegisterCoreAlias() { var application = Type2Service(typeof(Application)); Instance(application, this); @@ -483,10 +511,13 @@ protected virtual void RegisterCoreAlias() /// /// 注册核心服务 /// - protected virtual void RegisterCoreService() + private void RegisterCoreService() { var bindable = new BindData(this, null, null, false); - this.Singleton((_, __) => new GlobalDispatcher((paramInfos, userParams) => GetDependencies(bindable, paramInfos, userParams))).Alias(); + this.Singleton( + (_, __) => new GlobalDispatcher( + (paramInfos, userParams) => GetDependencies(bindable, paramInfos, userParams))) + .Alias(); } /// @@ -499,5 +530,29 @@ private Type GetProviderBaseType(IServiceProvider provider) var providerType = provider as IServiceProviderType; return providerType == null ? provider.GetType() : providerType.BaseType; } + + /// + /// 启动迭代器 + /// + /// 迭代程序 + private void StartCoroutine(IEnumerator coroutine) + { + var stack = new Stack(); + stack.Push(coroutine); + do + { + coroutine = stack.Pop(); + while (coroutine.MoveNext()) + { + if (!(coroutine.Current is IEnumerator nextCoroutine)) + { + continue; + } + + stack.Push(coroutine); + coroutine = nextCoroutine; + } + } while (stack.Count > 0); + } } } \ No newline at end of file diff --git a/src/CatLib.Core/CatLib/ApplicationEvents.cs b/src/CatLib.Core/CatLib/ApplicationEvents.cs index 69fd2da..0ba14a8 100644 --- a/src/CatLib.Core/CatLib/ApplicationEvents.cs +++ b/src/CatLib.Core/CatLib/ApplicationEvents.cs @@ -44,7 +44,18 @@ public sealed class ApplicationEvents /// /// 当初始化进行时 /// - public static readonly string OnIniting = "CatLib.ApplicationEvents.OnIniting"; + [System.Obsolete("Please use " + nameof(OnProviderInit))] + public static readonly string OnIniting = "CatLib.ApplicationEvents.OnProviderInit"; + + /// + /// 当服务提供者初始化进行前 + /// + public static readonly string OnProviderInit = "CatLib.ApplicationEvents.OnProviderInit"; + + /// + /// 当服务提供者初始化结束后 + /// + public static readonly string OnProviderInited = "CatLib.ApplicationEvents.OnProviderInited"; /// /// 当初始化完成之后 diff --git a/src/CatLib.Core/CatLib/DebugLevels.cs b/src/CatLib.Core/CatLib/DebugLevels.cs index 11a00bb..ed4c7c3 100644 --- a/src/CatLib.Core/CatLib/DebugLevels.cs +++ b/src/CatLib.Core/CatLib/DebugLevels.cs @@ -21,7 +21,7 @@ public enum DebugLevels /// /// 生产环境 /// - [Obsolete("Please use Production")] + [Obsolete("Please use " + nameof(Production))] Prod, /// @@ -37,7 +37,7 @@ public enum DebugLevels /// /// 开发者模式 /// - [Obsolete("Please use Development")] + [Obsolete("Please use " + nameof(Development))] Dev, /// diff --git a/src/CatLib.Core/CatLib/Events/DispatcherExtend.cs b/src/CatLib.Core/CatLib/Events/DispatcherExtend.cs index c708155..d4e47df 100644 --- a/src/CatLib.Core/CatLib/Events/DispatcherExtend.cs +++ b/src/CatLib.Core/CatLib/Events/DispatcherExtend.cs @@ -29,7 +29,7 @@ public static class CatLibDispatcherExtend /// 事件对象 public static IEvent On(this IDispatcher dispatcher, string eventName, object target, string method = null) { - Guard.NotEmptyOrNull(eventName, "eventName"); + Guard.NotEmptyOrNull(eventName, nameof(eventName)); Guard.Requires(method != string.Empty); Guard.Requires(target != null); @@ -49,7 +49,7 @@ public static IEvent On(this IDispatcher dispatcher, string eventName, object ta /// public static IEvent On(this IDispatcher dispatcher, string eventName, object target, MethodInfo methodInfo, object group = null) { - Guard.NotEmptyOrNull(eventName, "eventName"); + Guard.NotEmptyOrNull(eventName, nameof(eventName)); Guard.Requires(methodInfo != null); if (!methodInfo.IsStatic) @@ -278,9 +278,7 @@ public static IEvent Listen(this IDispatcher dispatcher internal static IGlobalDispatcher ToGlobalDispatcher(this IDispatcher dispatcher) { var originalDispatcher = dispatcher as IOriginalDispatcher; - var globalDispatcher = originalDispatcher == null - ? null - : originalDispatcher.Dispatcher as IGlobalDispatcher; + var globalDispatcher = originalDispatcher?.Dispatcher as IGlobalDispatcher; if (globalDispatcher != null) { return globalDispatcher; diff --git a/src/CatLib.Core/CatLib/Facade.cs b/src/CatLib.Core/CatLib/Facade.cs index 7ff6f4b..fad8315 100644 --- a/src/CatLib.Core/CatLib/Facade.cs +++ b/src/CatLib.Core/CatLib/Facade.cs @@ -60,20 +60,14 @@ static Facade() /// /// 门面实例 /// - public static TService Instance - { - get { return HasInstance ? instance : Resolve(); } - } + public static TService Instance => HasInstance ? instance : Resolve(); /// /// 是否拥有门面实例 /// 如果为非静态绑定那么永远返回false /// 门面实例判断不能代替:Container.HasInstance /// - internal static bool HasInstance - { - get { return binder != null && binder.IsStatic && !released && instance != null; } - } + internal static bool HasInstance => binder != null && binder.IsStatic && !released && instance != null; /// /// 构建一个服务实例 diff --git a/src/CatLib.Core/CatLib/Facades/Template/Managed.cs b/src/CatLib.Core/CatLib/Facades/Template/Managed.cs index b0fcd4a..41d0179 100644 --- a/src/CatLib.Core/CatLib/Facades/Template/Managed.cs +++ b/src/CatLib.Core/CatLib/Facades/Template/Managed.cs @@ -31,8 +31,8 @@ public abstract class Managed : Facade /// public static event Action OnResolving { - add { Instance.OnResolving += value; } - remove { Instance.OnResolving -= value; } + add => Instance.OnResolving += value; + remove => Instance.OnResolving -= value; } /// diff --git a/src/CatLib.Core/CatLib/Facades/Template/SingleManaged.cs b/src/CatLib.Core/CatLib/Facades/Template/SingleManaged.cs index d9f0286..39d4c62 100644 --- a/src/CatLib.Core/CatLib/Facades/Template/SingleManaged.cs +++ b/src/CatLib.Core/CatLib/Facades/Template/SingleManaged.cs @@ -31,8 +31,8 @@ public abstract class SingleManaged : Managed public static event Action OnRelease { - add { Instance.OnRelease += value; } - remove { Instance.OnRelease -= value; } + add => Instance.OnRelease += value; + remove => Instance.OnRelease -= value; } /// diff --git a/src/CatLib.Core/CatLib/Facades/Template/SingleManager.cs b/src/CatLib.Core/CatLib/Facades/Template/SingleManager.cs index 5b1ce73..1dfcd3c 100644 --- a/src/CatLib.Core/CatLib/Facades/Template/SingleManager.cs +++ b/src/CatLib.Core/CatLib/Facades/Template/SingleManager.cs @@ -37,9 +37,6 @@ public static TExtend Get(string name = null) /// /// 默认的扩展实现 /// - public static TExtend Default - { - get { return Instance.Default; } - } + public static TExtend Default => Instance.Default; } } diff --git a/src/CatLib.Core/CatLib/ICoroutineInit.cs b/src/CatLib.Core/CatLib/ICoroutineInit.cs new file mode 100644 index 0000000..24415a3 --- /dev/null +++ b/src/CatLib.Core/CatLib/ICoroutineInit.cs @@ -0,0 +1,26 @@ +/* + * 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; + +namespace CatLib +{ + /// + /// 协同初始化 + /// + public interface ICoroutineInit + { + /// + /// 服务提供者初始化 + /// + IEnumerator CoroutineInit(); + } +} diff --git a/src/CatLib.Core/CatLib/ServiceProvider.cs b/src/CatLib.Core/CatLib/ServiceProvider.cs index 3601aec..935b292 100644 --- a/src/CatLib.Core/CatLib/ServiceProvider.cs +++ b/src/CatLib.Core/CatLib/ServiceProvider.cs @@ -9,13 +9,15 @@ * Document: http://catlib.io/ */ +using System.Collections; + namespace CatLib { /// /// 基础服务提供者 /// [ExcludeFromCodeCoverage] - public abstract class ServiceProvider : IServiceProvider + public abstract class ServiceProvider : IServiceProvider, ICoroutineInit { /// /// 服务提供者初始化 @@ -24,9 +26,20 @@ public virtual void Init() { } + /// + /// 协同初始化 + /// + /// 迭代器 + public virtual IEnumerator CoroutineInit() + { + yield break; + } + /// /// 当注册服务提供者 /// - public abstract void Register(); + public virtual void Register() + { + } } } diff --git a/src/CatLib.Core/Properties/AssemblyInfo.cs b/src/CatLib.Core/Properties/AssemblyInfo.cs index a563c3d..023140c 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.2.0.0")] -[assembly: AssemblyFileVersion("1.2.12.0")] +[assembly: AssemblyVersion("1.3.0.0")] +[assembly: AssemblyFileVersion("1.3.0.0")] [assembly: InternalsVisibleTo("Assembly-CSharp-Editor"), InternalsVisibleTo("Assembly-CSharp-Editor-firstpass"), diff --git a/src/CatLib.Core/Support/Attribute/PriorityAttribute.cs b/src/CatLib.Core/Support/Attribute/PriorityAttribute.cs index 4716852..f8188d4 100644 --- a/src/CatLib.Core/Support/Attribute/PriorityAttribute.cs +++ b/src/CatLib.Core/Support/Attribute/PriorityAttribute.cs @@ -22,7 +22,7 @@ public class PriorityAttribute : Attribute /// /// 优先级 /// - public int Priorities { get; private set; } + public int Priorities { get; } /// /// 优先级(0最高) diff --git a/src/CatLib.Core/Support/Container/BindData.cs b/src/CatLib.Core/Support/Container/BindData.cs index 4ec16ab..1c30d27 100644 --- a/src/CatLib.Core/Support/Container/BindData.cs +++ b/src/CatLib.Core/Support/Container/BindData.cs @@ -22,12 +22,12 @@ internal sealed class BindData : Bindable, IBindData /// /// 服务实现,执行这个委托将会获得服务实例 /// - public Func Concrete { get; private set; } + public Func Concrete { get; } /// /// 当前绑定的服务是否是静态服务 /// - public bool IsStatic { get; private set; } + public bool IsStatic { get; } /// /// 服务构造修饰器 @@ -47,7 +47,7 @@ internal sealed class BindData : Bindable, IBindData /// 服务实现 /// 服务是否是静态的 public BindData(Container container, string service, Func concrete, bool isStatic) - :base(container, service) + : base(container, service) { Concrete = concrete; IsStatic = isStatic; @@ -73,7 +73,7 @@ public IBindData Alias(string alias) lock (SyncRoot) { GuardIsDestroy(); - Guard.NotEmptyOrNull(alias, "alias"); + Guard.NotEmptyOrNull(alias, nameof(alias)); Container.Alias(alias, Service); return this; } @@ -89,7 +89,7 @@ public IBindData Tag(string tag) lock (SyncRoot) { GuardIsDestroy(); - Guard.NotEmptyOrNull(tag, "tag"); + Guard.NotEmptyOrNull(tag, nameof(tag)); Container.Tag(tag, Service); return this; } @@ -102,7 +102,7 @@ public IBindData Tag(string tag) /// 服务绑定数据 public IBindData OnResolving(Func func) { - Guard.NotNull(func, "func"); + Guard.NotNull(func, nameof(func)); lock (SyncRoot) { GuardIsDestroy(); @@ -122,10 +122,10 @@ public IBindData OnResolving(Func func) /// 服务绑定数据 public IBindData OnRelease(Action action) { - Guard.NotNull(action, "action"); + Guard.NotNull(action, nameof(action)); if (!IsStatic) { - throw new RuntimeException("Service [" + Service + "] is not Singleton(Static) Bind , Can not call OnRelease()."); + throw new RuntimeException($"Service [{Service}] is not Singleton(Static) Bind , Can not call {nameof(OnRelease)}()."); } lock (SyncRoot) { @@ -175,6 +175,7 @@ internal void TriggerRelease(object obj) { return; } + foreach (var action in release) { action.Invoke(this, obj); diff --git a/src/CatLib.Core/Support/Container/Bindable.cs b/src/CatLib.Core/Support/Container/Bindable.cs index 892fc45..fd794d6 100644 --- a/src/CatLib.Core/Support/Container/Bindable.cs +++ b/src/CatLib.Core/Support/Container/Bindable.cs @@ -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 RuntimeException($"Needs [{needs}] is already exist."); } contextual.Add(needs, given); } @@ -102,8 +102,7 @@ internal string GetContextual(string needs) { return needs; } - string contextualNeeds; - return contextual.TryGetValue(needs, out contextualNeeds) ? contextualNeeds : needs; + return contextual.TryGetValue(needs, out string contextualNeeds) ? contextualNeeds : needs; } /// @@ -150,7 +149,7 @@ protected Bindable(Container container, string service) /// 绑定关系临时数据 public IGivenData Needs(string service) { - Guard.NotEmptyOrNull(service, "service"); + Guard.NotEmptyOrNull(service, nameof(service)); lock (SyncRoot) { GuardIsDestroy(); diff --git a/src/CatLib.Core/Support/Container/Container.cs b/src/CatLib.Core/Support/Container/Container.cs index 9dd9510..fae1239 100644 --- a/src/CatLib.Core/Support/Container/Container.cs +++ b/src/CatLib.Core/Support/Container/Container.cs @@ -31,6 +31,11 @@ public class Container : IContainer /// private readonly Dictionary instances; + /// + /// 单例化对象的反查表 + /// + private readonly Dictionary instancesReverse; + /// /// 服务的别名(key: 别名 , value: 映射的服务名) /// @@ -72,6 +77,11 @@ public class Container : IContainer /// private readonly HashSet resolved; + /// + /// 单例服务构建时序 + /// + private readonly SortSet instanceTiming; + /// /// 重定义事件 /// @@ -95,33 +105,27 @@ public class Container : IContainer /// /// 编译堆栈 /// - private readonly Stack buildStack; + protected Stack BuildStack { get; } /// - /// 编译堆栈 + /// 用户参数堆栈 /// - protected Stack BuildStack - { - get { return buildStack; } - } + protected Stack UserParamsStack { get; } /// - /// 用户参数堆栈 + /// 是否在清空过程中 /// - private readonly Stack userParamsStack; + private bool flushing; /// - /// 用户参数堆栈 + /// 单例化Id /// - protected Stack UserParamsStack - { - get { return userParamsStack; } - } + private int instanceId; /// - /// 是否在清空过程中 + /// 服务禁用字符 /// - private bool flushing; + private static readonly char[] ServiceBanChars = { '@', ':' ,'$'}; /// /// 构造一个容器 @@ -134,6 +138,7 @@ public Container(int prime = 64) aliases = new Dictionary(prime * 4); aliasesReverse = new Dictionary>(prime * 4); instances = new Dictionary(prime * 4); + instancesReverse = new Dictionary(prime * 4); binds = new Dictionary(prime * 4); resolving = new List>((int)(prime * 0.25)); release = new List>((int)(prime * 0.25)); @@ -141,12 +146,15 @@ public Container(int prime = 64) findType = new SortSet, int>(); findTypeCache = new Dictionary(prime * 4); rebound = new Dictionary>>(prime); - buildStack = new Stack(32); - userParamsStack = new Stack(32); + instanceTiming = new SortSet(); + instanceTiming.ReverseIterator(false); + BuildStack = new Stack(32); + UserParamsStack = new Stack(32); injectTarget = typeof(InjectAttribute); methodContainer = new MethodContainer(this, GetDependencies); flushing = false; + instanceId = 0; } /// @@ -158,19 +166,17 @@ public Container(int prime = 64) /// null或者中的元素为null或者空字符串 public void Tag(string tag, params string[] service) { - Guard.NotEmptyOrNull(tag, "tag"); - Guard.NotNull(service, "service"); - Guard.CountGreaterZero(service, "service"); - Guard.ElementNotEmptyOrNull(service, "service"); + Guard.NotEmptyOrNull(tag, nameof(tag)); + Guard.NotNull(service, nameof(service)); + Guard.CountGreaterZero(service, nameof(service)); + Guard.ElementNotEmptyOrNull(service, nameof(service)); lock (syncRoot) { GuardFlushing(); - List list; - if (!tags.TryGetValue(tag, out list)) + if (!tags.TryGetValue(tag, out List list)) { tags[tag] = list = new List(); - } list.AddRange(service); } @@ -185,13 +191,12 @@ public void Tag(string tag, params string[] service) /// null或者空字符串 public object[] Tagged(string tag) { - Guard.NotEmptyOrNull(tag, "tag"); + Guard.NotEmptyOrNull(tag, nameof(tag)); lock (syncRoot) { - List services; - if (!tags.TryGetValue(tag, out services)) + if (!tags.TryGetValue(tag, out List services)) { - throw new RuntimeException("Tag [" + tag + "] is not exist."); + throw new RuntimeException($"Tag [{tag}] is not exist."); } var result = new object[services.Count]; @@ -212,12 +217,11 @@ public object[] Tagged(string tag) /// null或者空字符串 public IBindData GetBind(string service) { - Guard.NotEmptyOrNull(service, "service"); + Guard.NotEmptyOrNull(service, nameof(service)); lock (syncRoot) { service = AliasToService(service); - BindData bindData; - return binds.TryGetValue(service, out bindData) ? bindData : null; + return binds.TryGetValue(service, out BindData bindData) ? bindData : null; } } @@ -238,7 +242,7 @@ public bool HasBind(string service) /// 是否已经静态化 public bool HasInstance(string service) { - Guard.NotEmptyOrNull(service, "service"); + Guard.NotEmptyOrNull(service, nameof(service)); lock (syncRoot) { service = AliasToService(service); @@ -253,7 +257,7 @@ public bool HasInstance(string service) /// 是否已经被解决过 public bool IsResolved(string service) { - Guard.NotEmptyOrNull(service, "service"); + Guard.NotEmptyOrNull(service, nameof(service)); lock (syncRoot) { service = AliasToService(service); @@ -268,7 +272,7 @@ public bool IsResolved(string service) /// 是否可以生成服务 public bool CanMake(string service) { - Guard.NotEmptyOrNull(service, "service"); + Guard.NotEmptyOrNull(service, nameof(service)); lock (syncRoot) { service = AliasToService(service); @@ -315,12 +319,12 @@ public bool IsAlias(string name) /// ,null或者空字符串 public IContainer Alias(string alias, string service) { - Guard.NotEmptyOrNull(alias, "alias"); - Guard.NotEmptyOrNull(service, "service"); + Guard.NotEmptyOrNull(alias, nameof(alias)); + Guard.NotEmptyOrNull(service, nameof(service)); if (alias == service) { - throw new RuntimeException("Alias is Same as Service Name: [" + alias + "]."); + throw new RuntimeException($"Alias is same as service name: [{alias}]."); } alias = FormatService(alias); @@ -331,18 +335,18 @@ public IContainer Alias(string alias, string service) GuardFlushing(); if (aliases.ContainsKey(alias)) { - throw new RuntimeException("Alias [" + alias + "] is already exists."); + 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()."); + throw new CodeStandardException( + $"You must {nameof(Bind)}() or {nameof(Instance)}() serivce before you can call {nameof(Alias)}()."); } aliases.Add(alias, service); - List serviceList; - if (!aliasesReverse.TryGetValue(service, out serviceList)) + if (!aliasesReverse.TryGetValue(service, out List serviceList)) { aliasesReverse[service] = serviceList = new List(); } @@ -382,12 +386,13 @@ public bool BindIf(string service, Func concrete, /// 服务绑定数据 public bool BindIf(string service, Type concrete, bool isStatic, out IBindData bindData) { - if (IsUnableType(concrete)) + if (!IsUnableType(concrete)) { - bindData = null; - return false; + return BindIf(service, WrapperTypeBuilder(service, concrete), isStatic, out bindData); } - return BindIf(service, WrapperTypeBuilder(service, concrete), isStatic, out bindData); + + bindData = null; + return false; } /// @@ -400,10 +405,10 @@ public bool BindIf(string service, Type concrete, bool isStatic, out IBindData b /// null或者空字符串 public IBindData Bind(string service, Type concrete, bool isStatic) { - Guard.NotNull(concrete, "concrete"); + Guard.NotNull(concrete, nameof(concrete)); if (IsUnableType(concrete)) { - throw new RuntimeException("Bind type [" + concrete + "] can not built"); + throw new RuntimeException($"Bind type [{concrete}] can not built"); } return Bind(service, WrapperTypeBuilder(service, concrete), isStatic); } @@ -419,8 +424,10 @@ public IBindData Bind(string service, Type concrete, bool isStatic) /// null public IBindData Bind(string service, Func concrete, bool isStatic) { - Guard.NotEmptyOrNull(service, "service"); - Guard.NotNull(concrete, "concrete"); + Guard.NotEmptyOrNull(service, nameof(service)); + Guard.NotNull(concrete, nameof(concrete)); + GuardServiceName(service); + service = FormatService(service); lock (syncRoot) { @@ -428,34 +435,36 @@ public IBindData Bind(string service, Func concret if (binds.ContainsKey(service)) { - throw new RuntimeException("Bind [" + service + "] already exists."); + throw new RuntimeException($"Bind [{service}] already exists."); } if (instances.ContainsKey(service)) { - throw new RuntimeException("Instances [" + service + "] is already exists."); + throw new RuntimeException($"Instances [{service}] is already exists."); } if (aliases.ContainsKey(service)) { - throw new RuntimeException("Aliase [" + service + "] is already exists."); + throw new RuntimeException($"Aliase [{service}] is already exists."); } var bindData = new BindData(this, service, concrete, isStatic); binds.Add(service, bindData); - if (IsResolved(service)) + if (!IsResolved(service)) { - if (isStatic) - { - // 如果为 静态的 那么直接解决这个服务 - // 在服务静态化的过程会触发 TriggerOnRebound - Resolve(service); - } - else - { - TriggerOnRebound(service); - } + return bindData; + } + + if (isStatic) + { + // 如果为 静态的 那么直接解决这个服务 + // 在服务静态化的过程会触发 TriggerOnRebound + Resolve(service); + } + else + { + TriggerOnRebound(service); } return bindData; @@ -472,6 +481,7 @@ public IBindData Bind(string service, Func concret public IMethodBind BindMethod(string method, object target, MethodInfo call) { GuardFlushing(); + GuardMethodName(method); return methodContainer.Bind(method, target, call); } @@ -497,6 +507,7 @@ public void UnbindMethod(object target) /// 调用结果 public object Invoke(string method, params object[] userParams) { + GuardConstruct(nameof(Invoke)); return methodContainer.Invoke(method, userParams); } @@ -515,6 +526,7 @@ public object Call(object target, MethodInfo methodInfo, params object[] userPar { Guard.Requires(target != null); } + GuardConstruct(nameof(Call)); var parameter = methodInfo.GetParameters(); @@ -544,10 +556,7 @@ public object Make(string service, params object[] userParams) /// /// 服务名或者别名 /// 服务实例,如果构造失败那么返回null - public object this[string service] - { - get { return Make(service); } - } + public object this[string service] => Make(service); /// /// 获取一个回调,当执行回调可以生成指定的服务 @@ -570,10 +579,13 @@ public Func Factory(string service, params object[] userParams) /// 被修饰器处理后的新的实例 public object Instance(string service, object instance) { - Guard.NotEmptyOrNull(service, "service"); + Guard.NotEmptyOrNull(service, nameof(service)); + lock (syncRoot) { GuardFlushing(); + GuardServiceName(service); + service = AliasToService(service); var bindData = GetBind(service); @@ -581,7 +593,7 @@ public object Instance(string service, object instance) { if (!bindData.IsStatic) { - throw new RuntimeException("Service [" + service + "] is not Singleton(Static) Bind."); + throw new RuntimeException($"Service [{service}] is not Singleton(Static) Bind."); } instance = ((BindData)bindData).TriggerResolving(instance); } @@ -590,13 +602,30 @@ public object Instance(string service, object instance) bindData = MakeEmptyBindData(service); } - var isResolved = IsResolved(service); + instance = TriggerOnResolving(bindData, instance); + + if (instance != null + && instancesReverse.TryGetValue(instance, out string realService) + && realService != service) + { + throw new CodeStandardException($"The instance has been registered as a singleton in {realService}"); + } + var isResolved = IsResolved(service); Release(service); - instance = TriggerOnResolving(bindData, instance); instances.Add(service, instance); + if (instance != null) + { + instancesReverse.Add(instance, service); + } + + if (!instanceTiming.Contains(service)) + { + instanceTiming.Add(service, instanceId++); + } + if (isResolved) { TriggerOnRebound(service, instance); @@ -612,13 +641,12 @@ public object Instance(string service, object instance) /// 服务名或别名 public bool Release(string service) { - Guard.NotEmptyOrNull(service, "service"); + Guard.NotEmptyOrNull(service, nameof(service)); lock (syncRoot) { service = AliasToService(service); - object instance; - if (!instances.TryGetValue(service, out instance)) + if (!instances.TryGetValue(service, out object instance)) { return false; } @@ -626,9 +654,20 @@ public bool Release(string service) var bindData = GetBindFillable(service); bindData.TriggerRelease(instance); TriggerOnRelease(bindData, instance); - DisposeInstance(instance); + + if (instance != null) + { + DisposeInstance(instance); + instancesReverse.Remove(instance); + } + instances.Remove(service); + if (!HasOnReboundCallbacks(service)) + { + instanceTiming.Remove(service); + } + return true; } } @@ -641,7 +680,7 @@ public bool Release(string service) /// 当前容器实例 public IContainer OnFindType(Func finder, int priority = int.MaxValue) { - Guard.NotNull(finder, "finder"); + Guard.NotNull(finder, nameof(finder)); lock (syncRoot) { GuardFlushing(); @@ -657,7 +696,7 @@ public IContainer OnFindType(Func finder, int priority = int.MaxVa /// 当前容器实例 public IContainer OnRelease(Action callback) { - Guard.NotNull(callback, "callback"); + Guard.NotNull(callback, nameof(callback)); lock (syncRoot) { GuardFlushing(); @@ -673,7 +712,7 @@ public IContainer OnRelease(Action callback) /// 当前容器对象 public IContainer OnResolving(Func callback) { - Guard.NotNull(callback, "callback"); + Guard.NotNull(callback, nameof(callback)); lock (syncRoot) { GuardFlushing(); @@ -690,14 +729,19 @@ public IContainer OnResolving(Func callback) /// 服务容器 public IContainer OnRebound(string service, Action callback) { - Guard.NotNull(callback, "callback"); + Guard.NotNull(callback, nameof(callback)); lock (syncRoot) { GuardFlushing(); service = AliasToService(service); - List> list; - if (!rebound.TryGetValue(service, out list)) + if (!IsResolved(service) && !CanMake(service)) + { + throw new CodeStandardException( + $"Must be monitored if the service can be make, Please {nameof(Bind)} or {nameof(Instance)} first."); + } + + if (!rebound.TryGetValue(service, out List> list)) { rebound[service] = list = new List>(); } @@ -737,10 +781,7 @@ public void Unbind(string service) { service = AliasToService(service); var bind = GetBind(service); - if (bind != null) - { - bind.Unbind(); - } + bind?.Unbind(); } /// @@ -753,11 +794,13 @@ public virtual void Flush() try { flushing = true; - foreach (var service in Dict.Keys(instances)) + foreach (var service in instanceTiming) { Release(service); } + Guard.Requires(instances.Count <= 0); + tags.Clear(); aliases.Clear(); aliasesReverse.Clear(); @@ -768,10 +811,12 @@ public virtual void Flush() resolved.Clear(); findType.Clear(); findTypeCache.Clear(); - buildStack.Clear(); - userParamsStack.Clear(); + BuildStack.Clear(); + UserParamsStack.Clear(); rebound.Clear(); methodContainer.Flush(); + instanceTiming.Clear(); + instanceId = 0; } finally { @@ -799,8 +844,7 @@ internal void Unbind(IBindable bindable) lock (syncRoot) { Release(bindable.Service); - List serviceList; - if (aliasesReverse.TryGetValue(bindable.Service, out serviceList)) + if (aliasesReverse.TryGetValue(bindable.Service, out List serviceList)) { foreach (var alias in serviceList) { @@ -838,8 +882,8 @@ public void Flash(Action callback, params KeyValuePair[] service // 所以我们抛出一个异常来终止该操作。 if (HasBind(service.Key)) { - throw new RuntimeException("Flash service [" + service.Key + - "] name has be used for bind or alias."); + throw new RuntimeException( + $"Flash service [{service.Key}] name has be used for {nameof(Bind)} or {nameof(Alias)}."); } } catch @@ -928,11 +972,13 @@ protected virtual object GetDependenciesFromUserParams(ParameterInfo baseParam, { var userParam = userParams[n]; - if (ChangeType(ref userParam, baseParam.ParameterType)) + if (!ChangeType(ref userParam, baseParam.ParameterType)) { - Arr.RemoveAt(ref userParams, n); - return userParam; + continue; } + + Arr.RemoveAt(ref userParams, n); + return userParam; } return null; @@ -1133,15 +1179,32 @@ protected virtual object ResloveClass(Bindable makeServiceBindData, string servi /// 推测的服务 protected virtual object SpeculationServiceByParamName(Bindable makeServiceBindData, string paramName, Type paramType) { - var service = makeServiceBindData.GetContextual("@" + paramName); - - if (!CanMake(service)) + foreach (var tag in GetVariableTags()) { - return null; + var service = makeServiceBindData.GetContextual($"{tag}{paramName}"); + + if (!CanMake(service)) + { + continue; + } + + var instance = Make(service); + if (ChangeType(ref instance, paramType)) + { + return instance; + } } - var instance = Make(service); - return ChangeType(ref instance, paramType) ? instance : null; + return null; + } + + /// + /// 获取变量标签 + /// + /// 变量标签 + protected virtual char[] GetVariableTags() + { + return new [] {'$', '@'}; } /// @@ -1151,7 +1214,7 @@ protected virtual object SpeculationServiceByParamName(Bindable makeServiceBindD protected virtual string GetBuildStackDebugMessage() { var previous = string.Join(", ", BuildStack.ToArray()); - return " While building stack [" + previous + "]."; + return $" While building stack [{previous}]."; } /// @@ -1163,15 +1226,9 @@ protected virtual string GetBuildStackDebugMessage() /// 运行时异常 protected virtual UnresolvableException MakeBuildFaildException(string makeService, Type makeServiceType, Exception innerException) { - string message; - if (makeServiceType != null) - { - message = "Class [" + makeServiceType + "] build faild. Service is [" + makeService + "]."; - } - else - { - message = "Service [" + makeService + "] is not exists."; - } + var message = makeServiceType != null + ? $"Class [{makeServiceType}] build faild. Service is [{makeService}]." + : $"Service [{makeService}] is not exists."; message += GetBuildStackDebugMessage(); message += GetInnerExceptionMessage(innerException); @@ -1199,7 +1256,7 @@ protected virtual string GetInnerExceptionMessage(Exception innerException) } stack.Append(innerException); } while ((innerException = innerException.InnerException) != null); - return " InnerException message stack: [" + stack + "]"; + return $" InnerException message stack: [{stack}]"; } /// @@ -1210,8 +1267,8 @@ protected virtual string GetInnerExceptionMessage(Exception innerException) /// 运行时异常 protected virtual UnresolvableException MakeUnresolvablePrimitiveException(string name, Type declaringClass) { - var message = "Unresolvable primitive dependency , resolving [" + name + "] in class [" + declaringClass + "]"; - return new UnresolvableException(message); + return new UnresolvableException( + $"Unresolvable primitive dependency , resolving [{name}] in class [{declaringClass}]"); } /// @@ -1221,7 +1278,7 @@ protected virtual UnresolvableException MakeUnresolvablePrimitiveException(strin /// 运行时异常 protected virtual RuntimeException MakeCircularDependencyException(string service) { - var message = "Circular dependency detected while for [" + service + "]."; + var message = $"Circular dependency detected while for [{service}]."; message += GetBuildStackDebugMessage(); return new RuntimeException(message); } @@ -1279,9 +1336,7 @@ protected virtual void GuardResolveInstance(object instance, string makeService) /// 服务类型 protected virtual Type SpeculatedServiceType(string service) { - Type result; - - if (findTypeCache.TryGetValue(service, out result)) + if (findTypeCache.TryGetValue(service, out Type result)) { return result; } @@ -1335,7 +1390,8 @@ protected virtual void AttributeInject(Bindable makeServiceBindData, object make 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 + "]."); + 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); @@ -1427,7 +1483,7 @@ protected virtual object[] GetDependencies(Bindable makeServiceBindData, Paramet var baseParam = baseParams[i]; // 使用参数匹配器对参数进行匹配,参数匹配器是最先进行的,因为他们的匹配精度是最准确的 - var param = (matcher == null) ? null : matcher(baseParam); + var param = matcher?.Invoke(baseParam); // 当容器发现开发者使用 object 或者 object[] 作为参数类型时 // 我们尝试将所有用户传入的用户参数紧缩注入 @@ -1457,15 +1513,15 @@ 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() + "]"; + 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 + "]."; + error += $" Make service is [{needService}]."; } throw new UnresolvableException(error); @@ -1512,6 +1568,39 @@ protected virtual object[] GetConstructorsInjectParams(Bindable makeServiceBindD throw exception; } + /// + /// 验证构建状态 + /// + /// 函数名 + protected virtual void GuardConstruct(string method) + { + } + + /// + /// 验证服务名有效性 + /// + /// 服务名 + protected virtual void GuardServiceName(string service) + { + foreach (var c in ServiceBanChars) + { + if (service.IndexOf(c) >= 0) + { + throw new CodeStandardException( + $"Service name {service} contains disabled characters : {c}. please use Alias replacement"); + } + } + } + + /// + /// 验证函数名有效性 + /// + /// 函数名 + protected virtual void GuardMethodName(string method) + { + + } + /// /// 验证重置状态 /// @@ -1519,7 +1608,7 @@ private void GuardFlushing() { if (flushing) { - throw new RuntimeException("Container is flushing can not "); + throw new CodeStandardException("Container is flushing can not do it"); } } @@ -1531,8 +1620,7 @@ private void GuardFlushing() private string AliasToService(string service) { service = FormatService(service); - string alias; - return aliases.TryGetValue(service, out alias) ? alias : service; + return aliases.TryGetValue(service, out string alias) ? alias : service; } /// @@ -1590,8 +1678,7 @@ private void TriggerOnRebound(string service, object instance = null) instance = Make(service); } } - }, Pair(typeof(IBindData), bind), - Pair(typeof(BindData), bind)); + }, Pair(typeof(IBindData), bind)); } /// @@ -1600,8 +1687,7 @@ private void TriggerOnRebound(string service, object instance = null) /// 实例 private void DisposeInstance(object obj) { - var disposable = obj as IDisposable; - if (disposable != null) + if (obj is IDisposable disposable) { disposable.Dispose(); } @@ -1621,11 +1707,22 @@ private KeyValuePair Pair(Type type, object instance) /// /// 获取重定义的服务所对应的回调 /// + /// 服务名 /// 回调列表 private IList> GetOnReboundCallbacks(string service) { - List> result; - return !rebound.TryGetValue(service, out result) ? null : result; + return !rebound.TryGetValue(service, out List> result) ? null : result; + } + + /// + /// 是否拥有重定义的服务所对应的回调 + /// + /// 服务名 + /// 是否存在回调 + private bool HasOnReboundCallbacks(string service) + { + var result = GetOnReboundCallbacks(service); + return result != null && result.Count > 0; } /// @@ -1650,24 +1747,24 @@ private BindData MakeEmptyBindData(string service) /// 服务实例 private object Resolve(string service, params object[] userParams) { - Guard.NotEmptyOrNull(service, "service"); + GuardConstruct(nameof(Make)); + Guard.NotEmptyOrNull(service, nameof(service)); lock (syncRoot) { service = AliasToService(service); - object instance; - if (instances.TryGetValue(service, out instance)) + if (instances.TryGetValue(service, out object instance)) { return instance; } - if (buildStack.Contains(service)) + if (BuildStack.Contains(service)) { throw MakeCircularDependencyException(service); } - buildStack.Push(service); - userParamsStack.Push(userParams); + BuildStack.Push(service); + UserParamsStack.Push(userParams); try { var bindData = GetBindFillable(service); @@ -1677,8 +1774,8 @@ private object Resolve(string service, params object[] userParams) } finally { - userParamsStack.Pop(); - buildStack.Pop(); + UserParamsStack.Pop(); + BuildStack.Pop(); } } } @@ -1754,8 +1851,7 @@ private object CreateInstance(Bindable makeServiceBindData, Type makeServiceType /// 服务绑定数据 private BindData GetBindFillable(string service) { - BindData bindData; - return service != null && binds.TryGetValue(service, out bindData) + return service != null && binds.TryGetValue(service, out BindData bindData) ? bindData : MakeEmptyBindData(service); } @@ -1786,12 +1882,11 @@ private Func MakeParamsMatcher(IParams[] tables) { // 默认匹配器策略将会将参数名和参数表的参数名进行匹配 // 最先匹配到的有效参数值将作为返回值返回 - return (parameterInfo) => + return parameterInfo => { foreach (var table in tables) { - object result; - if (!table.TryGetValue(parameterInfo.Name, out result)) + if (!table.TryGetValue(parameterInfo.Name, out object result)) { continue; } diff --git a/src/CatLib.Core/Support/Container/ContainerExtend.cs b/src/CatLib.Core/Support/Container/ContainerExtend.cs index d448391..b603aa1 100644 --- a/src/CatLib.Core/Support/Container/ContainerExtend.cs +++ b/src/CatLib.Core/Support/Container/ContainerExtend.cs @@ -96,6 +96,16 @@ public static bool IsAlias(this IContainer container) return container.IsAlias(container.Type2Service(typeof(TService))); } + /// + /// 为服务设定一个别名 + /// + /// 别名 + /// 服务名 + public static IContainer Alias(this IContainer container) + { + return container.Alias(container.Type2Service(typeof(TAlias)), container.Type2Service(typeof(TService))); + } + /// /// 常规绑定一个服务 /// @@ -375,7 +385,7 @@ public static bool SingletonIf(this IContainer container, string service, /// 调用方法 public static IMethodBind BindMethod(this IContainer container, string method, object target, string call = null) { - Guard.NotEmptyOrNull(method, "method"); + Guard.NotEmptyOrNull(method, nameof(method)); Guard.Requires(target != null); return container.BindMethod(method, target, target.GetType().GetMethod(call ?? Str.Method(method))); @@ -592,7 +602,7 @@ public static void Call(this IContainer container, Action(target != null); - Guard.NotEmptyOrNull(method, "method"); + Guard.NotEmptyOrNull(method, nameof(method)); var methodInfo = target.GetType().GetMethod(method); return container.Call(target, methodInfo, userParams); @@ -692,8 +702,7 @@ public static TService Make(this IContainer container, params object[] 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); + container.BindIf(service, type, false, out IBindData binder); return container.Make(service, userParams); } @@ -748,7 +757,7 @@ public static IContainer OnResolving(this IContainer container, Action c public static void Watch(this IContainer container, string service, object target, string method) { Guard.Requires(target != null); - Guard.NotEmptyOrNull(method, "method"); + Guard.NotEmptyOrNull(method, nameof(method)); var methodInfo = target.GetType().GetMethod(method); container.Watch(service, target, methodInfo); diff --git a/src/CatLib.Core/Support/Container/GivenData.cs b/src/CatLib.Core/Support/Container/GivenData.cs index b842305..ff12eb2 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, nameof(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 9a7e314..312f87c 100644 --- a/src/CatLib.Core/Support/Container/IContainer.cs +++ b/src/CatLib.Core/Support/Container/IContainer.cs @@ -152,6 +152,7 @@ public interface IContainer /// /// 服务名或者别名 /// 服务实例 + /// 被修饰器处理后的新的实例 object Instance(string service, object instance); /// @@ -206,7 +207,7 @@ public interface IContainer Func Factory(string service, params object[] userParams); /// - /// 以全局的方式为服务设定一个别名 + /// 为服务设定一个别名 /// /// 别名 /// 映射到的服务名 diff --git a/src/CatLib.Core/Support/Container/IMethodBind.cs b/src/CatLib.Core/Support/Container/IMethodBind.cs index c72a4f7..805ccd7 100644 --- a/src/CatLib.Core/Support/Container/IMethodBind.cs +++ b/src/CatLib.Core/Support/Container/IMethodBind.cs @@ -10,7 +10,7 @@ */ namespace CatLib -{ +{ /// /// 方法绑定数据 /// diff --git a/src/CatLib.Core/Support/Container/InjectAttribute.cs b/src/CatLib.Core/Support/Container/InjectAttribute.cs index a62e0e4..ed91b9f 100644 --- a/src/CatLib.Core/Support/Container/InjectAttribute.cs +++ b/src/CatLib.Core/Support/Container/InjectAttribute.cs @@ -24,7 +24,7 @@ public class InjectAttribute : Attribute /// /// 注入服务的别名或者服务名 /// - public string Alias { get; private set; } + public string Alias { get; } /// /// 声明注入 diff --git a/src/CatLib.Core/Support/Container/MethodBind.cs b/src/CatLib.Core/Support/Container/MethodBind.cs index 3ecceec..2ff254f 100644 --- a/src/CatLib.Core/Support/Container/MethodBind.cs +++ b/src/CatLib.Core/Support/Container/MethodBind.cs @@ -16,22 +16,22 @@ namespace CatLib /// /// 方法绑定数据 /// - internal sealed class MethodBind : Bindable , IMethodBind + internal sealed class MethodBind : Bindable, IMethodBind { /// /// 方法信息 /// - public MethodInfo MethodInfo { get; private set; } + public MethodInfo MethodInfo { get; } /// /// 调用目标 /// - public object Target { get; private set; } + public object Target { get; } /// /// 参数表 /// - public ParameterInfo[] ParameterInfos { get; private set; } + public ParameterInfo[] ParameterInfos { get; } /// /// 方法容器 @@ -47,7 +47,7 @@ internal sealed class MethodBind : Bindable , IMethodBind /// 调用目标 /// 调用方法 public MethodBind(MethodContainer methodContainer, Container container, string service, object target, MethodInfo call) - :base(container, service) + : base(container, service) { this.methodContainer = methodContainer; Target = target; diff --git a/src/CatLib.Core/Support/Container/MethodContainer.cs b/src/CatLib.Core/Support/Container/MethodContainer.cs index 093a413..182b40d 100644 --- a/src/CatLib.Core/Support/Container/MethodContainer.cs +++ b/src/CatLib.Core/Support/Container/MethodContainer.cs @@ -68,7 +68,7 @@ internal MethodContainer(Container container, Func public IMethodBind Bind(string method, object target, MethodInfo methodInfo) { - Guard.NotEmptyOrNull(method, "method"); + Guard.NotEmptyOrNull(method, nameof(method)); Guard.Requires(methodInfo != null); if (!methodInfo.IsStatic) @@ -80,7 +80,7 @@ public IMethodBind Bind(string method, object target, MethodInfo methodInfo) { if (methodMappings.ContainsKey(method)) { - throw new RuntimeException("Method [" + method + "] is already bind"); + throw new RuntimeException($"Method [{method}] is already {nameof(Bind)}"); } var methodBind = new MethodBind(this, container, method, target, methodInfo); @@ -91,8 +91,7 @@ public IMethodBind Bind(string method, object target, MethodInfo methodInfo) return methodBind; } - List targetMappings; - if (!targetToMethodsMappings.TryGetValue(target, out targetMappings)) + if (!targetToMethodsMappings.TryGetValue(target, out List targetMappings)) { targetToMethodsMappings[target] = targetMappings = new List(); } @@ -110,12 +109,11 @@ public IMethodBind Bind(string method, object target, MethodInfo methodInfo) /// 方法调用结果 public object Invoke(string method, params object[] userParams) { - Guard.NotEmptyOrNull(method, "method"); + Guard.NotEmptyOrNull(method, nameof(method)); lock (syncRoot) { - MethodBind methodBind; - if (!methodMappings.TryGetValue(method, out methodBind)) + if (!methodMappings.TryGetValue(method, out MethodBind methodBind)) { throw MakeMethodNotFoundException(method); } @@ -178,8 +176,7 @@ internal void Unbind(MethodBind methodBind) return; } - List methods; - if (!targetToMethodsMappings.TryGetValue(methodBind.Target, out methods)) + if (!targetToMethodsMappings.TryGetValue(methodBind.Target, out List methods)) { return; } @@ -199,8 +196,7 @@ internal void Unbind(MethodBind methodBind) /// 对象信息 private void UnbindWithObject(object target) { - List methods; - if (!targetToMethodsMappings.TryGetValue(target, out methods)) + if (!targetToMethodsMappings.TryGetValue(target, out List methods)) { return; } @@ -229,7 +225,7 @@ public void Flush() /// private RuntimeException MakeMethodNotFoundException(string method) { - return new RuntimeException("Method [" + method + "] is not found."); + return new RuntimeException($"Method [{method}] is not found."); } } } diff --git a/src/CatLib.Core/Support/Container/Params.cs b/src/CatLib.Core/Support/Container/Params.cs index 28c731f..bbbb15f 100644 --- a/src/CatLib.Core/Support/Container/Params.cs +++ b/src/CatLib.Core/Support/Container/Params.cs @@ -66,14 +66,8 @@ public Params(IDictionary args) /// 参数值 public object this[string key] { - get - { - return table[key]; - } - set - { - table[key] = value; - } + get => table[key]; + set => table[key] = value; } /// diff --git a/src/CatLib.Core/Support/Container/UnresolvableException.cs b/src/CatLib.Core/Support/Container/UnresolvableException.cs index 2d1bb5e..1ce6b8d 100644 --- a/src/CatLib.Core/Support/Container/UnresolvableException.cs +++ b/src/CatLib.Core/Support/Container/UnresolvableException.cs @@ -22,7 +22,7 @@ public class UnresolvableException : RuntimeException /// /// 未能解决异常 /// - public UnresolvableException() : base() + public UnresolvableException() { } diff --git a/src/CatLib.Core/Support/Events/Dispatcher.cs b/src/CatLib.Core/Support/Events/Dispatcher.cs index e123372..0aac21b 100644 --- a/src/CatLib.Core/Support/Events/Dispatcher.cs +++ b/src/CatLib.Core/Support/Events/Dispatcher.cs @@ -43,10 +43,7 @@ public class Dispatcher : IDispatcher /// /// 跳出标记 /// - protected virtual object BreakFlag - { - get { return false; } - } + protected virtual object BreakFlag => false; /// /// 构建一个事件调度器 @@ -127,7 +124,7 @@ public object TriggerHalt(string eventName, params object[] payloads) /// 事件对象 public IEvent On(string eventName, Func execution, object group = null) { - Guard.NotEmptyOrNull(eventName, "eventName"); + Guard.NotEmptyOrNull(eventName, nameof(eventName)); Guard.Requires(execution != null); lock (syncRoot) @@ -143,8 +140,7 @@ public IEvent On(string eventName, Func execution, obj return result; } - List listener; - if (!groupMapping.TryGetValue(group, out listener)) + if (!groupMapping.TryGetValue(group, out List listener)) { groupMapping[group] = listener = new List(); } @@ -286,8 +282,7 @@ private IEnumerable GetListeners(string eventName) { var outputs = new List(); - List result; - if (listeners.TryGetValue(eventName, out result)) + if (listeners.TryGetValue(eventName, out List result)) { outputs.AddRange(result); } @@ -309,8 +304,7 @@ private IEnumerable GetListeners(string eventName) /// 事件名 private void DismissEventName(string eventName) { - List events; - if (!listeners.TryGetValue(eventName, out events)) + if (!listeners.TryGetValue(eventName, out List events)) { return; } @@ -327,8 +321,7 @@ private void DismissEventName(string eventName) /// 事件名 private void DismissWildcardEventName(string eventName) { - KeyValuePair> events; - if (!wildcardListeners.TryGetValue(eventName, out events)) + if (!wildcardListeners.TryGetValue(eventName, out KeyValuePair> events)) { return; } @@ -345,8 +338,7 @@ private void DismissWildcardEventName(string eventName) /// 事件解除目标 private void DismissTargetObject(object target) { - List events; - if (!groupMapping.TryGetValue(target, out events)) + if (!groupMapping.TryGetValue(target, out List events)) { return; } @@ -365,8 +357,7 @@ private void Forget(IEvent target) { lock (syncRoot) { - List events; - if (target.Group != null && groupMapping.TryGetValue(target.Group, out events)) + if (target.Group != null && groupMapping.TryGetValue(target.Group, out List events)) { events.Remove(target); if (events.Count <= 0) @@ -392,8 +383,7 @@ private void Forget(IEvent target) /// 事件对象 private void ForgetListen(IEvent target) { - List events; - if (!listeners.TryGetValue(target.Name, out events)) + if (!listeners.TryGetValue(target.Name, out List events)) { return; } @@ -411,8 +401,7 @@ private void ForgetListen(IEvent target) /// 事件对象 private void ForgetWildcardListen(IEvent target) { - KeyValuePair> wildcardEvents; - if (!wildcardListeners.TryGetValue(target.Name, out wildcardEvents)) + if (!wildcardListeners.TryGetValue(target.Name, out KeyValuePair> wildcardEvents)) { return; } @@ -433,8 +422,7 @@ private void ForgetWildcardListen(IEvent target) /// 监听事件 private IEvent SetupListen(string eventName, Func execution, object group) { - List listener; - if (!listeners.TryGetValue(eventName, out listener)) + if (!listeners.TryGetValue(eventName, out List listener)) { listeners[eventName] = listener = new List(); } @@ -453,8 +441,7 @@ private IEvent SetupListen(string eventName, Func exec /// 监听事件 private IEvent SetupWildcardListen(string eventName, Func execution, object group) { - KeyValuePair> listener; - if (!wildcardListeners.TryGetValue(eventName, out listener)) + if (!wildcardListeners.TryGetValue(eventName, out KeyValuePair> listener)) { wildcardListeners[eventName] = listener = new KeyValuePair>(new Regex(Str.AsteriskWildcard(eventName)), new List()); diff --git a/src/CatLib.Core/Support/Events/Event.cs b/src/CatLib.Core/Support/Events/Event.cs index cc62f99..8f54761 100644 --- a/src/CatLib.Core/Support/Events/Event.cs +++ b/src/CatLib.Core/Support/Events/Event.cs @@ -21,12 +21,12 @@ internal class Event : IEvent /// /// 原始事件名 /// - public string Name { get; private set; } + public string Name { get; } /// /// 事件根源对象 /// - public object Group { get; private set; } + public object Group { get; } /// /// 依赖解决器 diff --git a/src/CatLib.Core/Support/Exception/AssertException.cs b/src/CatLib.Core/Support/Exception/AssertException.cs index 91167d2..9003f19 100644 --- a/src/CatLib.Core/Support/Exception/AssertException.cs +++ b/src/CatLib.Core/Support/Exception/AssertException.cs @@ -22,7 +22,7 @@ public class AssertException : RuntimeException /// /// 断言异常 /// - public AssertException() : base() + public AssertException() { } diff --git a/src/CatLib.Core/Support/Exception/CodeStandardException.cs b/src/CatLib.Core/Support/Exception/CodeStandardException.cs new file mode 100644 index 0000000..5dd8719 --- /dev/null +++ b/src/CatLib.Core/Support/Exception/CodeStandardException.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 CodeStandardException : RuntimeException + { + /// + /// 代码规范异常 + /// + public CodeStandardException() + { + + } + + /// + /// 代码规范异常 + /// + /// 异常消息 + public CodeStandardException(string message) : base(message) + { + } + + /// + /// 代码规范异常 + /// + /// 异常消息 + /// 内部异常 + public CodeStandardException(string message, Exception innerException) : base(message, innerException) + { + } + } +} \ No newline at end of file diff --git a/src/CatLib.Core/Support/Exception/RuntimeException.cs b/src/CatLib.Core/Support/Exception/RuntimeException.cs index 22b5a5b..2eec8b0 100644 --- a/src/CatLib.Core/Support/Exception/RuntimeException.cs +++ b/src/CatLib.Core/Support/Exception/RuntimeException.cs @@ -21,9 +21,9 @@ public class RuntimeException : Exception /// /// 运行时异常 /// - public RuntimeException() : base() + public RuntimeException() { - + } /// diff --git a/src/CatLib.Core/Support/FilterChain/FilterChain.cs b/src/CatLib.Core/Support/FilterChain/FilterChain.cs index 883062d..64d1971 100644 --- a/src/CatLib.Core/Support/FilterChain/FilterChain.cs +++ b/src/CatLib.Core/Support/FilterChain/FilterChain.cs @@ -28,13 +28,7 @@ public sealed class FilterChain : IFilterChain /// /// 过滤器列表 /// - public Action>[] FilterList - { - get - { - return filterList.ToArray(); - } - } + public Action>[] FilterList => filterList.ToArray(); /// /// 堆栈 用于解决内部递归调用过滤器链所出现的问题 @@ -71,10 +65,7 @@ public void Do(TIn inData, Action then = null) { if (filterList.Count <= 0) { - if (then != null) - { - then.Invoke(inData); - } + then?.Invoke(inData); return; } @@ -96,10 +87,7 @@ private Action Next(Action then) stack.Push(++index); if (index >= filterList.Count) { - if (then != null) - { - then.Invoke(inData); - } + then?.Invoke(inData); return; } filterList[index].Invoke(inData, Next(then)); @@ -122,13 +110,7 @@ public sealed class FilterChain : IFilterChain /// /// 过滤器列表 /// - public Action>[] FilterList - { - get - { - return filterList.ToArray(); - } - } + public Action>[] FilterList => filterList.ToArray(); /// /// 堆栈 用于解决内部递归调用过滤器链所出现的问题 @@ -166,10 +148,7 @@ public void Do(TIn inData, TOut outData, Action then = null) { if (filterList.Count <= 0) { - if (then != null) - { - then.Invoke(inData, outData); - } + then?.Invoke(inData, outData); return; } @@ -191,10 +170,7 @@ private Action Next(Action then) stack.Push(++index); if (index >= filterList.Count) { - if (then != null) - { - then.Invoke(inData, outData); - } + then?.Invoke(inData, outData); return; } filterList[index].Invoke(inData, outData, Next(then)); @@ -218,13 +194,7 @@ public sealed class FilterChain : IFilterChain /// 过滤器列表 /// - public Action>[] FilterList - { - get - { - return filterList.ToArray(); - } - } + public Action>[] FilterList => filterList.ToArray(); /// /// 堆栈 用于解决内部递归调用过滤器链所出现的问题 @@ -263,10 +233,7 @@ public void Do(TIn inData, TOut outData, TException exception, Action Next(Action then) stack.Push(++index); if (index >= filterList.Count) { - if (then != null) - { - then.Invoke(inData, outData, exception); - } + then?.Invoke(inData, outData, exception); return; } filterList[index].Invoke(inData, outData, exception, Next(then)); diff --git a/src/CatLib.Core/Support/Guard/Guard.cs b/src/CatLib.Core/Support/Guard/Guard.cs index cdb526b..3ada7a7 100644 --- a/src/CatLib.Core/Support/Guard/Guard.cs +++ b/src/CatLib.Core/Support/Guard/Guard.cs @@ -25,7 +25,7 @@ public static class Guard /// 异常 /// 条件 [System.Diagnostics.DebuggerNonUserCode] - public static void Requires(bool condition) where TException : Exception , new() + public static void Requires(bool condition) where TException : Exception, new() { if (condition) { @@ -75,7 +75,7 @@ public static void ElementNotEmptyOrNull(IList argumentValue, string arg { if (string.IsNullOrEmpty(val)) { - throw new ArgumentNullException(argumentName, "Argument element can not be Empty or Null."); + throw new ArgumentNullException(argumentName, $"Argument element can not be {nameof(string.Empty)} or null."); } } } diff --git a/src/CatLib.Core/Support/QuickList/InternalList.cs b/src/CatLib.Core/Support/QuickList/InternalList.cs index b6ba248..7835846 100644 --- a/src/CatLib.Core/Support/QuickList/InternalList.cs +++ b/src/CatLib.Core/Support/QuickList/InternalList.cs @@ -49,13 +49,7 @@ internal InternalList(int capacity = 128) /// /// 偏移量 /// 元素 - internal TElement this[int offset] - { - get - { - return items[offset]; - } - } + internal TElement this[int offset] => items[offset]; /// /// 在指定位置插入元素 @@ -79,7 +73,7 @@ internal void InsertAt(TElement element, int offset) internal void RemoveAt(int offset) { Array.Copy(items, offset + 1, items, offset, Count - offset - 1); - Array.Clear(items , Count - 1 , 1); + Array.Clear(items, Count - 1, 1); --Count; } @@ -100,7 +94,7 @@ internal void RemoveRange(int start, int end) /// /// 元素 /// 偏移量 - internal void ReplaceAt(TElement element ,int offset) + internal void ReplaceAt(TElement element, int offset) { items[offset] = element; } diff --git a/src/CatLib.Core/Support/QuickList/QuickList.cs b/src/CatLib.Core/Support/QuickList/QuickList.cs index c9d2d39..236ce8e 100644 --- a/src/CatLib.Core/Support/QuickList/QuickList.cs +++ b/src/CatLib.Core/Support/QuickList/QuickList.cs @@ -20,7 +20,7 @@ namespace CatLib /// 快速列表 /// /// 元素 - [DebuggerDisplay("Count = {Count} , Length = {Length}")] + [DebuggerDisplay("Count = {" + nameof(Count) + "} , Length = {" + nameof(Length) + "}")] public sealed class QuickList : IQuickList { /// @@ -146,24 +146,12 @@ public bool MoveNext() /// /// 获取当前元素 /// - public TElement Current - { - get - { - return current; - } - } + public TElement Current => current; /// /// 获取当前元素 /// - object IEnumerator.Current - { - get - { - return current; - } - } + object IEnumerator.Current => current; /// /// 重置迭代器 @@ -211,18 +199,7 @@ public void Dispose() /// /// 同步锁 /// - private readonly object syncRoot = new object(); - - /// - /// 同步锁 - /// - public object SyncRoot - { - get - { - return syncRoot; - } - } + public object SyncRoot { get; } = new object(); /// /// 列表元素基数 @@ -298,7 +275,7 @@ public void Add(TElement element) /// 元素 public void Push(TElement element) { - Insert(element, tail, tail != null ? tail.List.Count - 1 : 0, true); + Insert(element, tail, tail?.List.Count - 1 ?? 0, true); } /// @@ -515,11 +492,12 @@ public TElement[] GetRange(int start, int end) for (var i = 0; i < elements.Length; i++) { elements[i] = node.List[offset]; - if (++offset >= fill) + if (++offset < fill) { - offset = 0; - node = node.Forward; + continue; } + offset = 0; + node = node.Forward; } return elements; } @@ -536,15 +514,13 @@ public TElement this[int index] { get { - int offset; - var node = FindByIndex(index, out offset); + var node = FindByIndex(index, out int offset); Guard.Requires(node != null); return node.List[offset]; } set { - int offset; - var node = FindByIndex(index, out offset); + var node = FindByIndex(index, out int offset); Guard.Requires(node != null); node.List.ReplaceAt(value, offset); } @@ -557,8 +533,7 @@ public TElement this[int index] /// 要插入的元素 public void InsertAfter(TElement finder, TElement insert) { - int offset; - var node = FindNode(finder, out offset); + var node = FindNode(finder, out int offset); if (node == null) { return; @@ -573,8 +548,7 @@ public void InsertAfter(TElement finder, TElement insert) /// 要插入的元素 public void InsertBefore(TElement finder, TElement insert) { - int offset; - var node = FindNode(finder, out offset); + var node = FindNode(finder, out int offset); if (node == null) { return; @@ -589,7 +563,7 @@ public void ReverseIterator() { forward = !forward; } - + /// /// 迭代器 /// @@ -686,8 +660,8 @@ private QuickListNode FindByIndex(int index, out int offset) /// 结点相对偏移量 private void Insert(TElement insert, QuickListNode node, int offset, bool after) { - bool full, fullNext, fullBackward, atTail, atHead; - full = fullNext = fullBackward = atTail = atHead = false; + bool fullNext, fullBackward, atTail, atHead; + var full = fullNext = fullBackward = atTail = atHead = false; QuickListNode newNode; if (node == null) @@ -747,22 +721,22 @@ private void Insert(TElement insert, QuickListNode node, int offset, bool after) //结点没有满,且是前插式 node.List.InsertAt(insert, offset); } - else if (atTail && node.Forward != null && !fullNext && after) + else if (atTail && node.Forward != null && !fullNext) { //如果当前结点满了,且是后插入尾部元素,并且下一个结点存在而且不是满的 //那么就会插入到下一个结点中的头部 newNode = node.Forward; newNode.List.UnShift(insert); } - else if (atHead && node.Backward != null && !fullBackward && !after) + else if (atHead && node.Backward != null && !fullBackward) { //如果当前结点满了,且是前插入头部元素,并且上一个结点存在而且不是满的 //那么就会插入到上一个结点中的尾部 newNode = node.Backward; newNode.List.Push(insert); } - else if (((atTail && node.Forward != null && fullNext && after) || - (atHead && node.Backward != null && fullBackward && !after))) + else if (((atTail && node.Forward != null && fullNext) || + (atHead && node.Backward != null && fullBackward))) { //如果当前结点是满的,且前置结点和后置结点都是满的那么 //就新建一个结点,插入在2个结点之间 @@ -802,8 +776,8 @@ private void AttemptMergeNode(QuickListNode node) return; } - QuickListNode backward, backwardBackward, forward, forwardForward; - backward = backwardBackward = forward = forwardForward = null; + QuickListNode backwardBackward, forward, forwardForward; + var backward = backwardBackward = forward = forwardForward = null; if (node.Backward != null) { @@ -826,13 +800,11 @@ private void AttemptMergeNode(QuickListNode node) if (AllowMerge(backward, backwardBackward)) { MergeNode(backward, backwardBackward, false); - backward = backwardBackward = null; } if (AllowMerge(forward, forwardForward)) { MergeNode(forward, forwardForward, true); - forward = forwardForward = null; } if (AllowMerge(node, node.Backward)) @@ -1028,11 +1000,7 @@ private QuickListNode MakeNode() /// 是否可以插入 private bool AllowInsert(QuickListNode node) { - if (node == null) - { - return false; - } - return node.List.Count < fill; + return node?.List.Count < fill; } } } diff --git a/src/CatLib.Core/Support/RingBuffer/RingBuffer.cs b/src/CatLib.Core/Support/RingBuffer/RingBuffer.cs index 9487edd..3152aa8 100644 --- a/src/CatLib.Core/Support/RingBuffer/RingBuffer.cs +++ b/src/CatLib.Core/Support/RingBuffer/RingBuffer.cs @@ -27,10 +27,7 @@ public sealed class RingBuffer : IRingBuffer, IDisposable /// /// 缓冲区容量 /// - public int Capacity - { - get { return (int)capacity; } - } + public int Capacity => (int)capacity; /// /// 缓冲区大小 @@ -81,18 +78,12 @@ public object SyncRoot /// /// 可写容量 /// - public int WriteableCapacity - { - get { return (int)GetCanWriteSize(); } - } + public int WriteableCapacity => (int)GetCanWriteSize(); /// /// 可读容量 /// - public int ReadableCapacity - { - get { return (int)GetCanReadSize(); } - } + public int ReadableCapacity => (int)GetCanReadSize(); /// /// 构建一个新的环型缓冲区实例 diff --git a/src/CatLib.Core/Support/SortSet/ISortSet.cs b/src/CatLib.Core/Support/SortSet/ISortSet.cs index bd86d56..953eca5 100644 --- a/src/CatLib.Core/Support/SortSet/ISortSet.cs +++ b/src/CatLib.Core/Support/SortSet/ISortSet.cs @@ -138,6 +138,12 @@ public interface ISortSet : IEnumerable /// void ReverseIterator(); + /// + /// 反转遍历顺序(并不是反转整个有序集) + /// + /// 指定的反转顺序 + void ReverseIterator(bool forward); + /// /// 获取第一个元素 /// diff --git a/src/CatLib.Core/Support/SortSet/SortSet.cs b/src/CatLib.Core/Support/SortSet/SortSet.cs index 1a1e17f..15550fe 100644 --- a/src/CatLib.Core/Support/SortSet/SortSet.cs +++ b/src/CatLib.Core/Support/SortSet/SortSet.cs @@ -20,7 +20,7 @@ namespace CatLib /// 有序集 /// 有序集使用分数进行排序(以小到大) /// - [DebuggerDisplay("Count = {Count}")] + [DebuggerDisplay("Count = {" + nameof(Count) + "}")] public sealed class SortSet : ISortSet where TScore : IComparable { @@ -142,7 +142,7 @@ public TElement Current { return current.Element; } - throw new RuntimeException("Can not get Current element"); + throw new RuntimeException($"Can not get {nameof(current)} element"); } } @@ -157,7 +157,7 @@ object IEnumerator.Current { return current.Element; } - throw new RuntimeException("Can not get Current element"); + throw new RuntimeException($"Can not get {nameof(current)} element"); } } @@ -177,11 +177,6 @@ public void Dispose() } } - /// - /// 同步锁 - /// - private readonly object syncRoot = new object(); - /// /// 是否是向前的迭代方向 /// @@ -235,13 +230,7 @@ public void Dispose() /// /// 同步锁 /// - public object SyncRoot - { - get - { - return syncRoot; - } - } + public object SyncRoot { get; } = new object(); /// /// 创建一个有序集 @@ -299,7 +288,16 @@ public void Clear() /// public void ReverseIterator() { - forward = !forward; + ReverseIterator(!forward); + } + + /// + /// 反转遍历顺序(并不是反转整个有序集) + /// + /// 反转顺序 + public void ReverseIterator(bool forward) + { + this.forward = forward; } /// @@ -308,7 +306,7 @@ public void ReverseIterator() /// 迭代器 public Enumerator GetEnumerator() { - return new Enumerator(this , forward); + return new Enumerator(this, forward); } /// @@ -378,8 +376,7 @@ public TElement Last() /// 元素 public TElement Shift() { - TElement result; - if (!Remove(header.Level[0].Forward, out result)) + if (!Remove(header.Level[0].Forward, out TElement result)) { throw new InvalidOperationException("SortSet is Null"); } @@ -392,8 +389,7 @@ public TElement Shift() /// 元素 public TElement Pop() { - TElement result; - if (!Remove(tail, out result)) + if (!Remove(tail, out TElement result)) { throw new InvalidOperationException("SortSet is Null"); } @@ -405,10 +401,7 @@ public TElement Pop() /// /// 排名,排名以0为底 /// 指定的元素 - public TElement this[int rank] - { - get { return GetElementByRank(rank); } - } + public TElement this[int rank] => GetElementByRank(rank); /// /// 插入记录 @@ -422,8 +415,7 @@ public void Add(TElement element, TScore score) Guard.Requires(score != null); //已经存在的元素先移除再添加 - TScore dictScore; - if (dict.TryGetValue(element, out dictScore)) + if (dict.TryGetValue(element, out TScore dictScore)) { Remove(element, dictScore); } @@ -451,8 +443,7 @@ public bool Contains(TElement element) public TScore GetScore(TElement element) { Guard.Requires(element != null); - TScore score; - if (!dict.TryGetValue(element, out score)) + if (!dict.TryGetValue(element, out TScore score)) { throw new KeyNotFoundException(); } @@ -524,8 +515,7 @@ public bool Remove(TElement element) { Guard.Requires(element != null); - TScore dictScore; - return dict.TryGetValue(element, out dictScore) && Remove(element, dictScore); + return dict.TryGetValue(element, out TScore dictScore) && Remove(element, dictScore); } /// @@ -620,8 +610,7 @@ public int RemoveRangeByScore(TScore startScore, TScore stopScore) public int GetRank(TElement element) { Guard.Requires(element != null); - TScore dictScore; - return dict.TryGetValue(element, out dictScore) ? GetRank(element, dictScore) : -1; + return dict.TryGetValue(element, out TScore dictScore) ? GetRank(element, dictScore) : -1; } /// @@ -739,7 +728,7 @@ public TElement GetElementByRank(int rank) if (Count > 0) { - throw new ArgumentOutOfRangeException("Rank is out of range [" + rank + "]"); + throw new ArgumentOutOfRangeException($"Rank is out of range [{rank}]"); } throw new InvalidOperationException("SortSet is Null"); @@ -1028,9 +1017,7 @@ private int GetRandomLevel() /// private int Compare(TScore left, TScore right) { - return comparer != null - ? comparer.Compare(left, right) - : left.CompareTo(right); + return comparer?.Compare(left, right) ?? left.CompareTo(right); } } } \ No newline at end of file diff --git a/src/CatLib.Core/Support/Storage/MemoryStorage.cs b/src/CatLib.Core/Support/Storage/MemoryStorage.cs index f439416..7e48328 100644 --- a/src/CatLib.Core/Support/Storage/MemoryStorage.cs +++ b/src/CatLib.Core/Support/Storage/MemoryStorage.cs @@ -68,12 +68,12 @@ public int GetFreeSize(long position) /// /// 当前存储最大内存使用量 /// - public long MaxMemoryUsable { get; private set; } + public long MaxMemoryUsable { get; } /// /// 单个内存块的大小 /// - public int BlockSize { get; private set; } + public int BlockSize { get; } /// /// 数据长度 @@ -141,7 +141,7 @@ public MemoryStorage(long maxMemoryUsable, int blockBuffer = 4096, int capacity MaxMemoryUsable = maxMemoryUsable; BlockSize = blockBuffer; length = 0; - storage = new BlockMeta[GetPrime(capacity)]; + storage = new BlockMeta[capacity.ToPrime()]; } /// @@ -364,13 +364,13 @@ private void EnsureStorageBlock(long value) return; } - var minBlockCount = (int) ((value / BlockSize) + ((value % BlockSize) == 0 ? 0 : 1)); + var minBlockCount = (int)((value / BlockSize) + ((value % BlockSize) == 0 ? 0 : 1)); if (storage.Length >= minBlockCount) { return; } - var newStorage = new BlockMeta[GetPrime(minBlockCount)]; + var newStorage = new BlockMeta[minBlockCount.ToPrime()]; Array.Copy(storage, 0, newStorage, 0, storage.Length); storage = newStorage; } @@ -400,28 +400,6 @@ protected virtual void Dispose(bool disposing) storage = null; } - /// - /// 计算规定值最近的二的次幂的容量 - /// - /// 规定值 - /// 容量 - private static int GetPrime(int min) - { - min = Math.Max(0, min); - - var result = 8192; - for (var i = 2; i < int.MaxValue; i = i << 1) - { - if (i >= min) - { - result = i; - break; - } - } - - return result; - } - /// /// 断言是否已经被释放 /// @@ -429,7 +407,7 @@ private void AssertDisabled() { if (Disabled) { - throw new ObjectDisposedException(null, "[" + GetType() + "] Stream is closed."); + throw new ObjectDisposedException(null, $"[{GetType()}] Stream is closed."); } } @@ -439,20 +417,22 @@ private void AssertDisabled() /// 内存占用 private void AssertMemoryUseable(long value) { - if (value > MaxMemoryUsable) + if (value <= MaxMemoryUsable) { - if (MaxMemoryUsable >= 1048576) - { - throw new OutOfMemoryException("Memory exceeds usage limit " + (MaxMemoryUsable / 1048576) + " MB"); - } + return; + } - if (MaxMemoryUsable >= 1024) - { - throw new OutOfMemoryException("Memory exceeds usage limit " + (MaxMemoryUsable / 1024) + " KB"); - } + if (MaxMemoryUsable >= 1048576) + { + throw new OutOfMemoryException($"Memory exceeds usage limit {MaxMemoryUsable / 1048576} MB"); + } - throw new OutOfMemoryException("Memory exceeds usage limit " + MaxMemoryUsable + " bit"); + if (MaxMemoryUsable >= 1024) + { + throw new OutOfMemoryException($"Memory exceeds usage limit {MaxMemoryUsable / 1024} KB"); } + + throw new OutOfMemoryException($"Memory exceeds usage limit {MaxMemoryUsable} bit"); } } } diff --git a/src/CatLib.Core/Support/Stream/CombineStream.cs b/src/CatLib.Core/Support/Stream/CombineStream.cs new file mode 100644 index 0000000..fb7be4b --- /dev/null +++ b/src/CatLib.Core/Support/Stream/CombineStream.cs @@ -0,0 +1,288 @@ +/* + * 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.IO; + +namespace CatLib +{ + /// + /// 组合流,允许将多个不同的流组合成一个流 + /// + public class CombineStream : WrapperStream + { + /// + /// 全局游标位置 + /// + private long globalPosition; + + /// + /// 当前所处的流 + /// + private int index; + + /// + /// 组合流 + /// + private readonly Stream[] streams; + + /// + /// 组合流的长度 + /// + private long length; + + /// + /// 组合流的长度 + /// + public override long Length + { + get + { + if (length >= 0) + { + return length; + } + + length = 0; + foreach (var stream in streams) + { + length += stream.Length; + } + return length; + } + } + + /// + /// 是否能够偏移 + /// + public override bool CanSeek + { + get + { + foreach (var stream in streams) + { + if (!stream.CanSeek) + { + return false; + } + } + return true; + } + } + + /// + /// 获取当前偏移量 + /// + public override long Position + { + get => globalPosition; + set => Seek(value, SeekOrigin.Begin); + } + + /// + /// 是否是可读的 + /// + public override bool CanRead => true; + + /// + /// 是否是可写的 + /// + public override bool CanWrite => false; + + /// + /// 组合流关闭时是否自动关闭流 + /// + private readonly bool autoClosed; + + /// + /// 构建一个组合流实例,允许将两个不同的流组合成一个流 + /// + /// 流 + /// 流 + /// 当组合流释放时是否自动关闭其中的流 + public CombineStream(Stream left, Stream right, bool closed = false) + : this(new[] { left, right }, closed) + { + } + + /// + /// 构建一个组合流实例,允许将多个流组合成一个流 + /// + /// 流 + /// 当组合流释放时是否自动关闭其中的流 + public CombineStream(Stream[] source, bool closed = false) + { + index = 0; + streams = source; + length = -1; + autoClosed = closed; + } + + /// + /// 设定位置偏移 + /// + /// 偏移量 + /// 偏移方向 + /// 当前偏移量 + public override long Seek(long offset, SeekOrigin origin) + { + if (!CanSeek) + { + throw new NotSupportedException($"{nameof(CombineStream)} not supported {nameof(Seek)}."); + } + + long newGloablPosition; + switch (origin) + { + case SeekOrigin.Begin: + newGloablPosition = offset; + break; + case SeekOrigin.Current: + newGloablPosition = globalPosition + offset; + break; + case SeekOrigin.End: + newGloablPosition = Length + offset; + break; + default: + throw new NotSupportedException($"Not support {nameof(SeekOrigin)}: {origin}"); + } + + if (newGloablPosition < 0 || newGloablPosition > Length) + { + throw new ArgumentOutOfRangeException($"{nameof(offset)} must large than zero or small then {nameof(Length)}"); + } + + long localPosition = 0; + var newIndex = index = CalculatedIndex(newGloablPosition, ref localPosition); + + streams[newIndex].Seek(localPosition, SeekOrigin.Begin); + while (++newIndex < streams.Length) + { + streams[newIndex].Seek(0, SeekOrigin.Begin); + } + + return globalPosition = newGloablPosition; + } + + /// + /// 计算偏移下标 + /// + /// 全局位置 + /// 本地偏移量 + protected int CalculatedIndex(long globalPosition, ref long localPosition) + { + long length = 0; + for (var i = 0; i < streams.Length; i++) + { + length += streams[i].Length; + if (globalPosition > length) + { + continue; + } + + localPosition = streams[i].Length - (length - globalPosition); + return i; + } + + throw new AssertException($"Failed to determine {nameof(localPosition)}"); + } + + /// + /// 读取组合流的数据到缓冲区 + /// + /// 缓冲区 + /// 缓冲区偏移量 + /// 希望读取的长度 + /// 实际读取的长度 + public override int Read(byte[] buffer, int offset, int count) + { + Guard.Requires(buffer != null); + Guard.Requires(offset >= 0); + Guard.Requires(count >= 0); + Guard.Requires(buffer.Length - offset >= count); + + var result = 0; + do + { + var read = streams[index].Read(buffer, offset, count); + if (read <= 0 && index < streams.Length - 1) + { + index++; + continue; + } + + if (read <= 0) + { + break; + } + + count -= read; + offset += read; + globalPosition += read; + result += read; + } while (count > 0); + + return result; + } + + /// + /// 写入数据到组合流 + /// + /// 缓冲区 + /// 偏移量 + /// + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException($"{nameof(CombineStream)} not supported {nameof(Write)}."); + } + + /// + /// 设定流的长度 + /// + /// 长度 + public override void SetLength(long value) + { + throw new NotSupportedException($"{nameof(CombineStream)} not supported {nameof(SetLength)}."); + } + + /// + /// Flush Stream + /// + public override void Flush() + { + throw new NotSupportedException($"{nameof(CombineStream)} not supported {nameof(Flush)}."); + } + + /// + /// 当组合流释放时 + /// + /// + protected override void Dispose(bool disposing) + { + try + { + if (!autoClosed) + { + return; + } + + foreach (var stream in streams) + { + stream?.Dispose(); + } + } + finally + { + base.Dispose(disposing); + } + } + } +} diff --git a/src/CatLib.Core/Support/Stream/PipelineStream.cs b/src/CatLib.Core/Support/Stream/PipelineStream.cs index 4bef0a9..3e0fc38 100644 --- a/src/CatLib.Core/Support/Stream/PipelineStream.cs +++ b/src/CatLib.Core/Support/Stream/PipelineStream.cs @@ -19,7 +19,7 @@ namespace CatLib /// 管道通讯流 /// 一读一写线程安全 /// - public class PipelineStream : Stream + public class PipelineStream : WrapperStream { /// /// 可以被读取的长度 @@ -59,19 +59,12 @@ public class PipelineStream : Stream /// /// 是否可以被读取 /// - public override bool CanRead - { - get { return count > 0 && !disabled; } - } + public override bool CanRead => count > 0 && !disabled; /// /// 是否可以被写入 /// - public override bool CanWrite - { - get { return count < capacity && !closed; } - } - + public override bool CanWrite => count < capacity && !closed; /// /// 当前流的位置 /// @@ -82,8 +75,8 @@ public override bool CanWrite /// public override long Position { - get { return position; } - set { throw new NotSupportedException(); } + get => position; + set => throw new NotSupportedException(); } /// @@ -94,26 +87,17 @@ public override long Position /// /// 流的长度 /// - public override long Length - { - get { return length; } - } + public override long Length => length; /// /// 是否能够设定偏移量 /// - public override bool CanSeek - { - get { return false; } - } + public override bool CanSeek => false; /// /// 是否已经关闭了流 /// - public bool Closed - { - get { return closed; } - } + public bool Closed => closed; /// /// 管道通讯流 @@ -204,10 +188,7 @@ public override int Read(byte[] buffer, int offset, int count) this.count -= read; position += read; - if (OnRead != null) - { - OnRead(this); - } + OnRead?.Invoke(this); return read; } @@ -280,7 +261,7 @@ protected void AssertClosed() { if (closed) { - throw new ObjectDisposedException("PipelineStream", "Stream is Closed Cannot write"); + throw new ObjectDisposedException(nameof(PipelineStream), $"Stream is {nameof(closed)} Cannot write"); } } @@ -291,7 +272,7 @@ protected void AssertDisabled() { if (disabled) { - throw new ObjectDisposedException("PipelineStream", "Stream is dispose"); + throw new ObjectDisposedException(nameof(PipelineStream), $"Stream is {disabled}"); } } diff --git a/src/CatLib.Core/Support/Stream/SegmentStream.cs b/src/CatLib.Core/Support/Stream/SegmentStream.cs new file mode 100644 index 0000000..36d3c55 --- /dev/null +++ b/src/CatLib.Core/Support/Stream/SegmentStream.cs @@ -0,0 +1,159 @@ +/* + * 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.IO; + +namespace CatLib +{ + /// + /// 分片流可以用于包装指定分片的流。 + /// 使指定分片的流访问起来就像传统流那样从开头到结尾。 + /// + public class SegmentStream : WrapperStream + { + /// + /// 基础流的初始的位置 + /// + private readonly long initialPosition; + + /// + /// 分片的大小 + /// + private readonly long partSize; + + /// + /// 构造一个分片流 + /// + /// 基础流 + /// 分片大小 + public SegmentStream(Stream stream, long partSize = 0) + : base(stream) + { + if (!stream.CanSeek) + { + throw new InvalidOperationException($"Base stream of {nameof(SegmentStream)} must be seekable"); + } + + initialPosition = stream.Position; + var remainingSize = stream.Length - stream.Position; + + if (partSize == 0 || remainingSize < partSize) + { + this.partSize = remainingSize; + } + else + { + this.partSize = partSize; + } + } + + /// + /// 剩余长度 + /// + private long RemainingSize => partSize - Position; + + /// + /// 流的长度 + /// + public override long Length + { + get + { + var length = base.Length - initialPosition; + if (length > partSize) + { + length = partSize; + } + return length; + } + } + + /// + /// 当前流的位置 + /// + public override long Position + { + get => base.Position - initialPosition; + set => base.Position = value; + } + + /// + /// 设定流的位置 + /// + /// 偏移量 + /// 偏移方向 + /// 流的位置 + public override long Seek(long offset, SeekOrigin origin) + { + long position; + switch (origin) + { + case SeekOrigin.Begin: + position = initialPosition + offset; + break; + case SeekOrigin.Current: + position = base.Position + offset; + break; + case SeekOrigin.End: + position = base.Position + partSize + offset; + break; + default: + throw new ArgumentOutOfRangeException(nameof(origin), origin, null); + } + + if (position < initialPosition) + { + position = initialPosition; + } + else if (position > initialPosition + partSize) + { + position = initialPosition + partSize; + } + + base.Seek(position, SeekOrigin.Begin); + return Position; + } + + /// + /// 读取流的数据到指定缓冲区 + /// + /// 指定缓冲区 + /// 缓冲区偏移量 + /// 希望读取的长度 + /// 实际读取的长度 + public override int Read(byte[] buffer, int offset, int count) + { + var bytesToRead = count < RemainingSize ? count : (int)RemainingSize; + return bytesToRead < 0 ? 0 : base.Read(buffer, offset, bytesToRead); + } + + /// + /// 设定流的长度 + /// + /// + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + /// + /// 将指定缓冲区的数据写入流中 + /// + /// 指定缓冲区 + /// 缓冲区偏移量 + /// 写入数据的长度 + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } + } +} diff --git a/src/CatLib.Core/Support/Stream/StorageStream.cs b/src/CatLib.Core/Support/Stream/StorageStream.cs index d3c5794..ccf4a0c 100644 --- a/src/CatLib.Core/Support/Stream/StorageStream.cs +++ b/src/CatLib.Core/Support/Stream/StorageStream.cs @@ -17,7 +17,7 @@ namespace CatLib /// /// 存储数据流 /// - public class StorageStream : Stream + public class StorageStream : WrapperStream { /// /// 当前游标所处的位置 @@ -49,10 +49,7 @@ public override long Position AssertDisabled(); return position; } - set - { - Seek(value, SeekOrigin.Begin); - } + set => Seek(value, SeekOrigin.Begin); } /// @@ -70,34 +67,22 @@ public override long Length /// /// 是否是可以写入数据的 /// - public override bool CanWrite - { - get { return !Disposed && writable; } - } + public override bool CanWrite => !Disposed && writable; /// /// 是否可以进行游标偏移 /// - public override bool CanSeek - { - get { return !Disposed; } - } + public override bool CanSeek => !Disposed; /// /// 是否可以读取数据 /// - public override bool CanRead - { - get { return !Disposed; } - } + public override bool CanRead => !Disposed; /// /// 是否已经被释放 /// - protected bool Disposed - { - get { return disabled || storage.Disabled; } - } + protected bool Disposed => disabled || storage.Disabled; /// /// 存储数据流 @@ -111,7 +96,7 @@ public StorageStream(IStorage storage, bool writable = true, int timeout = 1000) if (storage.Disabled) { - throw new ObjectDisposedException("storage", "Storage is disposed"); + throw new ObjectDisposedException(nameof(storage), $"Storage is {storage.Disabled}"); } this.storage = storage; @@ -173,17 +158,17 @@ public override long Seek(long offset, SeekOrigin origin) break; } default: - throw new ArgumentException("Unknow SeekOrigin"); + throw new ArgumentException($"Unknow {nameof(SeekOrigin)}:{origin}"); } if (tempPosition < 0) { - throw new IOException("seek position less than 0"); + throw new IOException($"Seek {position} less than 0"); } if (tempPosition > Length) { - throw new IOException("seek position is large then length(" + Length + ")"); + throw new IOException($"Seek {position} is large then length : {Length}"); } position = tempPosition; @@ -231,6 +216,7 @@ public override void SetLength(long value) /// /// 清除当前流的缓冲区 /// + [ExcludeFromCodeCoverage] public override void Flush() { // 只有存在数据落地或者转移的情况下此函数才有效 @@ -241,6 +227,7 @@ public override void Flush() /// 获取线程占用异常 /// /// 异常 + [ExcludeFromCodeCoverage] protected IOException GetOccupyException() { return new IOException("The resource is already occupied by other threads"); @@ -283,7 +270,7 @@ private void AssertDisabled() { if (Disposed) { - throw new ObjectDisposedException(null, "[" + GetType() + "] Stream is closed."); + throw new ObjectDisposedException(null, $"[{GetType()}] Stream is closed."); } } diff --git a/src/CatLib.Core/Support/Stream/WrapperStream.cs b/src/CatLib.Core/Support/Stream/WrapperStream.cs new file mode 100644 index 0000000..19b39f5 --- /dev/null +++ b/src/CatLib.Core/Support/Stream/WrapperStream.cs @@ -0,0 +1,126 @@ +/* + * 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.IO; + +namespace CatLib +{ + /// + /// 包装流 + /// + [ExcludeFromCodeCoverage] + public class WrapperStream : Stream + { + /// + /// 基础流 + /// + public Stream BaseStream { get; } + + /// + /// 流是否可读 + /// + public override bool CanRead => BaseStream.CanRead; + + /// + /// 流是否可以偏移 + /// + public override bool CanSeek => BaseStream.CanSeek; + + /// + /// 流是否可写 + /// + public override bool CanWrite => BaseStream.CanWrite; + + /// + /// 流的偏移位置 + /// + public override long Position + { + get => BaseStream.Position; + set => Seek(value, SeekOrigin.Begin); + } + + /// + /// 流的长度 + /// + public override long Length => BaseStream.Length; + + /// + /// 构建一个包装流 + /// + public WrapperStream() + { + BaseStream = this; + } + + /// + /// 构建一个包装流 + /// + /// 基础流 + public WrapperStream(Stream stream) + { + Guard.Requires(stream != null); + BaseStream = stream; + } + + /// + /// 偏移流到指定位置 + /// + /// 指定位置 + /// 偏移方向 + /// 新的位置 + public override long Seek(long offset, SeekOrigin origin) + { + return BaseStream.Seek(offset, origin); + } + + /// + /// 刷新流的缓冲区 + /// + public override void Flush() + { + BaseStream.Flush(); + } + + /// + /// 在流中写入指定缓冲区的数据 + /// + /// 指定缓冲区 + /// 指定缓冲区偏移量 + /// 写入的长度 + public override void Write(byte[] buffer, int offset, int count) + { + BaseStream.Write(buffer, offset, count); + } + + /// + /// 设定流的长度 + /// + /// 长度 + public override void SetLength(long value) + { + BaseStream.SetLength(value); + } + + /// + /// 读取流的数据到指定缓冲区 + /// + /// 指定缓冲区 + /// 指定缓冲区偏移量 + /// 读取的长度 + /// 实际读取的长度 + public override int Read(byte[] buffer, int offset, int count) + { + return BaseStream.Read(buffer, offset, count); + } + } +} diff --git a/src/CatLib.Core/Support/Template/IManaged.cs b/src/CatLib.Core/Support/Template/IManaged.cs index 44dd781..42a67ee 100644 --- a/src/CatLib.Core/Support/Template/IManaged.cs +++ b/src/CatLib.Core/Support/Template/IManaged.cs @@ -35,7 +35,7 @@ public interface IManaged /// 释放指定扩展的构建器 /// /// 扩展名 - [Obsolete("Please use RemoveExtend();")] + [Obsolete("Please use " + nameof(RemoveExtend) + "();")] void ReleaseExtend(string name = null); /// diff --git a/src/CatLib.Core/Support/Template/Managed.cs b/src/CatLib.Core/Support/Template/Managed.cs index b7e19b9..b1da623 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 RuntimeException($"Extend [{name}]({GetType()}) is already exists."); } extendBuilder.Add(name, builder); @@ -61,7 +61,7 @@ public void Extend(Func builder, string name = null) /// 释放指定扩展的构建器 /// /// 扩展名 - [Obsolete("Please use RemoveExtend();")] + [Obsolete("Please use " + nameof(RemoveExtend) + "();")] public void ReleaseExtend(string name = null) { RemoveExtend(name); @@ -102,10 +102,7 @@ protected virtual TInterface MakeExtend(string name) { var extend = GetExtend(name)(); - if (OnResolving != null) - { - OnResolving(extend); - } + OnResolving?.Invoke(extend); return extend; } @@ -140,10 +137,9 @@ private Func GetExtend(string name) { StandardName(ref name); - Func result; - if (!extendBuilder.TryGetValue(name, out result)) + if (!extendBuilder.TryGetValue(name, out Func result)) { - throw new RuntimeException("Can not find [" + name + "](" + GetType() + ") Extend."); + throw new RuntimeException($"Can not find [{name}]({GetType()}) Extend."); } return result; diff --git a/src/CatLib.Core/Support/Template/Manager.cs b/src/CatLib.Core/Support/Template/Manager.cs index 57a3156..dde2877 100644 --- a/src/CatLib.Core/Support/Template/Manager.cs +++ b/src/CatLib.Core/Support/Template/Manager.cs @@ -31,12 +31,6 @@ public TInterface Get(string name = null) /// /// 扩展名 /// 扩展实现 - public TInterface this[string name] - { - get - { - return Get(name); - } - } + public TInterface this[string name] => Get(name); } } diff --git a/src/CatLib.Core/Support/Template/SingleManaged.cs b/src/CatLib.Core/Support/Template/SingleManaged.cs index 22f21b0..2f0aaec 100644 --- a/src/CatLib.Core/Support/Template/SingleManaged.cs +++ b/src/CatLib.Core/Support/Template/SingleManaged.cs @@ -45,8 +45,7 @@ public void Release(string name = null) { StandardName(ref name); - TInterface extend; - if (!instances.TryGetValue(name, out extend)) + if (!instances.TryGetValue(name, out TInterface extend)) { return; } @@ -84,16 +83,9 @@ public virtual void Dispose() /// 扩展实现 private void InternalRelease(TInterface extend) { - if (OnRelease != null) - { - OnRelease(extend); - } - + OnRelease?.Invoke(extend); var dispose = extend as IDisposable; - if (dispose != null) - { - dispose.Dispose(); - } + dispose?.Dispose(); } /// @@ -105,8 +97,7 @@ protected override TInterface MakeExtend(string name) { StandardName(ref name); - TInterface extend; - if (instances.TryGetValue(name, out extend)) + if (instances.TryGetValue(name, out TInterface extend)) { return extend; } diff --git a/src/CatLib.Core/Support/Template/SingleManager.cs b/src/CatLib.Core/Support/Template/SingleManager.cs index 005be53..5fdf0b7 100644 --- a/src/CatLib.Core/Support/Template/SingleManager.cs +++ b/src/CatLib.Core/Support/Template/SingleManager.cs @@ -29,25 +29,13 @@ public TInterface Get(string name = null) /// /// 默认的扩展实现 /// - public TInterface Default - { - get - { - return this[null]; - } - } + public TInterface Default => this[null]; /// /// 获取指定的扩展实现 /// /// 扩展名 /// 扩展实现 - public TInterface this[string name] - { - get - { - return Get(name); - } - } + public TInterface this[string name] => Get(name); } } diff --git a/src/CatLib.Core/Support/Util/Arr.cs b/src/CatLib.Core/Support/Util/Arr.cs index ee7df94..4ecf352 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 { @@ -256,7 +257,7 @@ public static T[] Fill(int start, int length, T value, T[] source = null) Guard.Requires(start >= 0); Guard.Requires(length > 0); var count = start + length; - var requested = new T[source == null ? count : source.Length + count]; + var requested = new T[source?.Length + count ?? count]; if (start > 0 && source != null) { @@ -336,6 +337,30 @@ public static T[] Filter(T[] source, Predicate predicate) return elements; } + /// + /// 将规定迭代器中的每个值传给回调函数,如果回调函数返回 true,则把规定迭代器中的当前值加入结果数组中 + /// + /// 数组类型 + /// 规定迭代器 + /// 回调函数 + /// 需求数组 + public static T[] Filter(IEnumerable source, Predicate predicate) + { + Guard.Requires(source != null); + Guard.Requires(predicate != null); + + var results = new List(); + foreach (var result in source) + { + if (predicate.Invoke(result)) + { + results.Add(result); + } + } + + return results.ToArray(); + } + /// /// 将数组值传入用户自定义函数,自定义函数返回的值作为新的数组值 /// @@ -359,6 +384,27 @@ public static T[] Map(T[] source, Func callback) return requested; } + /// + /// 将迭代器的值传入用户自定义函数,自定义函数返回的值作为新的数组值 + /// + /// 数组类型 + /// 规定迭代器 + /// 自定义函数 + /// 处理后的数组 + public static T[] Map(IEnumerable source, Func callback) + { + Guard.Requires(source != null); + Guard.Requires(callback != null); + + var requested = new List(); + foreach (var value in source) + { + requested.Add(callback.Invoke(value)); + } + + return requested.ToArray(); + } + /// /// 删除数组中的最后一个元素,并将删除的元素作为返回值返回 /// @@ -413,7 +459,7 @@ public static string Reduce(T[] source, Func callback, obj { requested = callback.Invoke(requested, segments); } - return requested == null ? null : requested.ToString(); + return requested?.ToString(); } /// diff --git a/src/CatLib.Core/Support/Util/Dict.cs b/src/CatLib.Core/Support/Util/Dict.cs index dd8ee47..864c4fc 100644 --- a/src/CatLib.Core/Support/Util/Dict.cs +++ b/src/CatLib.Core/Support/Util/Dict.cs @@ -53,7 +53,7 @@ public static IDictionary Filter(IDictionary规定字典 /// 回调函数 /// 被移除的元素 - public static KeyValuePair[] Remove(IDictionary source + public static KeyValuePair[] Remove(IDictionary source , Func predicate) { Guard.Requires(source != null); @@ -100,7 +100,7 @@ public static void Modify(IDictionary source } } - if(elements == null) + if (elements == null) { return; } @@ -268,8 +268,7 @@ private static object GetValueByDepthArray(IDictionary dict, ref { while (true) { - object result; - if (!dict.TryGetValue(Arr.Pop(ref keys), out result) || keys.Length <= 0) + if (!dict.TryGetValue(Arr.Pop(ref keys), out object result) || keys.Length <= 0) { return result; } @@ -298,9 +297,8 @@ private static void SetValueByDepthArray(IDictionary dict, ref s return; } - object result; var key = Arr.Pop(ref keys); - if (!dict.TryGetValue(key, out result) || !(result is IDictionary)) + if (!dict.TryGetValue(key, out object result) || !(result is IDictionary)) { dict[key] = result = new Dictionary(); } @@ -336,9 +334,8 @@ private static bool RemoveValueByDepthArray(IDictionary dict, re return true; } - object result; var key = Arr.Pop(ref keys); - if (!dict.TryGetValue(key, out result) || !(result is IDictionary)) + if (!dict.TryGetValue(key, out object result) || !(result is IDictionary)) { return false; } diff --git a/src/CatLib.Core/Support/Util/Extension/IntExtension.cs b/src/CatLib.Core/Support/Util/Extension/IntExtension.cs index 39f2d1e..adeaca0 100644 --- a/src/CatLib.Core/Support/Util/Extension/IntExtension.cs +++ b/src/CatLib.Core/Support/Util/Extension/IntExtension.cs @@ -30,11 +30,12 @@ public static int ToPrime(this int min) var result = 0; for (var i = 2; i < int.MaxValue; i = i << 1) { - if (i >= min) + if (i < min) { - result = i; - break; + continue; } + result = i; + break; } return result; diff --git a/src/CatLib.Core/Support/Util/Extension/StreamExtension.cs b/src/CatLib.Core/Support/Util/Extension/StreamExtension.cs index 5d0fb40..26d2cb3 100644 --- a/src/CatLib.Core/Support/Util/Extension/StreamExtension.cs +++ b/src/CatLib.Core/Support/Util/Extension/StreamExtension.cs @@ -63,12 +63,18 @@ public static long AppendTo(this Stream source, Stream destination, byte[] buffe /// 字符串 public static string ToText(this Stream source, Encoding encoding = null, bool closed = true) { + Guard.Requires(source != null); try { + if (!source.CanRead) + { + throw new RuntimeException($"Can not read stream, {nameof(source.CanRead)} == false"); + } + encoding = encoding ?? Util.Encoding; - if (source is MemoryStream) + var memoryStream = source as MemoryStream; + if (memoryStream != null) { - var memoryStream = (MemoryStream) source; byte[] buffer; try { @@ -79,7 +85,7 @@ public static string ToText(this Stream source, Encoding encoding = null, bool c buffer = memoryStream.ToArray(); } - return encoding.GetString(buffer, 0, (int) memoryStream.Length); + return encoding.GetString(buffer, 0, (int)memoryStream.Length); } var length = 0; diff --git a/src/CatLib.Core/Support/Util/Str.cs b/src/CatLib.Core/Support/Util/Str.cs index f4c4fc2..57b0cc0 100644 --- a/src/CatLib.Core/Support/Util/Str.cs +++ b/src/CatLib.Core/Support/Util/Str.cs @@ -58,8 +58,8 @@ public static string Method(string pattern) for (var i = pattern.Length - 1; i >= 0; i--) { var segment = pattern[i]; - if ((segment >= 'A' && segment <= 'Z') - || (segment >= 'a' && segment <= 'z') + if ((segment >= 'A' && segment <= 'Z') + || (segment >= 'a' && segment <= 'z') || (segment >= '0' && segment <= '9') || segment == '_') { @@ -303,13 +303,8 @@ public static string After(string str, string search) Guard.Requires(str != null); Guard.Requires(search != null); - var index = str.IndexOf(search); - if (index < 0) - { - return str; - } - - return str.Substring(index + search.Length, str.Length - index - search.Length); + var index = str.IndexOf(search, StringComparison.Ordinal); + return index < 0 ? str : str.Substring(index + search.Length, str.Length - index - search.Length); } /// diff --git a/src/CatLib.Core/Support/Util/ThreadStatic.cs b/src/CatLib.Core/Support/Util/ThreadStatic.cs index 21a3587..61280ff 100644 --- a/src/CatLib.Core/Support/Util/ThreadStatic.cs +++ b/src/CatLib.Core/Support/Util/ThreadStatic.cs @@ -27,9 +27,6 @@ public static class ThreadStatic /// /// 默认缓冲区 /// - public static byte[] Buffer - { - get { return buffer; } - } + public static byte[] Buffer => buffer; } } diff --git a/src/CatLib.Core/Support/Util/Version.cs b/src/CatLib.Core/Support/Util/Version.cs index 43481ad..02ecaf0 100644 --- a/src/CatLib.Core/Support/Util/Version.cs +++ b/src/CatLib.Core/Support/Util/Version.cs @@ -27,18 +27,9 @@ public class Version /// /// 版本匹配正则式 /// - 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; - } - } + private static Regex VersionMatcher => versionMatcher ?? (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]))*?))?$") + ); /// /// 原始版本信息 @@ -208,10 +199,8 @@ public int Compare(string version) /// 右值 private int CompareBlock(string left, string right) { - int leftInt; - var leftIsInt = int.TryParse(left, out leftInt); - int rightInt; - var rightIsInt = int.TryParse(right, out rightInt); + var leftIsInt = int.TryParse(left, out int leftInt); + var rightIsInt = int.TryParse(right, out int rightInt); if (rightIsInt && leftIsInt) { @@ -234,7 +223,7 @@ private void GuardVersion(string version) { if (!VersionMatcher.IsMatch(version)) { - throw new RuntimeException("version is invalid"); + throw new RuntimeException($"{nameof(version)} is invalid : {version}"); } }