Auto status change to "Under Review"
Closed
Pull request !2
Created on
Tue, 02 Feb 2021 11:50:08,
- Fixed Safe.DisposeCollection NullReferenceException
- sync
- Добавлена метка v3.0.14 для набора изменений 95896f882995
- Added tests for Implab.ServiceHost.Unity configuration loader.
- Added IObservable to TraceRegistry
Pull request versions not available.
ver | Time | Author | Commit | Description | ||
---|---|---|---|---|---|---|
91 commits hidden, click expand to show them. |
The requested changes are too big and content was truncated. Show full diff
@@ -0,0 +1,18 | |||||
|
1 | { | |||
|
2 | "version": "0.2.0", | |||
|
3 | "configurations": [ | |||
|
4 | { | |||
|
5 | "name": ".NET Core Launch (console)", | |||
|
6 | "type": "coreclr", | |||
|
7 | "request": "launch", | |||
|
8 | "preLaunchTask": "build", | |||
|
9 | "program": "${workspaceRoot}/Implab.Playground/bin/Debug/netcoreapp2.0/Implab.Playground.dll", | |||
|
10 | "args": [ | |||
|
11 | "-f", "netcoreapp2.0" | |||
|
12 | ], | |||
|
13 | "cwd": "${workspaceRoot}/Implab.Playground", | |||
|
14 | "stopAtEntry": false, | |||
|
15 | "console": "internalConsole" | |||
|
16 | } | |||
|
17 | ] | |||
|
18 | } No newline at end of file |
@@ -0,0 +1,12 | |||||
|
1 | // Поместите параметры в этот файл, чтобы перезаписать параметры по умолчанию и пользовательские параметры. | |||
|
2 | { | |||
|
3 | "files.exclude": { | |||
|
4 | "**/.git": true, | |||
|
5 | "**/.svn": true, | |||
|
6 | "**/.hg": true, | |||
|
7 | "**/CVS": true, | |||
|
8 | "**/.DS_Store": true, | |||
|
9 | "**/bin": true, | |||
|
10 | "**/obj": true | |||
|
11 | } | |||
|
12 | } No newline at end of file |
@@ -0,0 +1,37 | |||||
|
1 | { | |||
|
2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 | |||
|
3 | // for the documentation about the tasks.json format | |||
|
4 | "version": "0.1.0", | |||
|
5 | "command": "dotnet", | |||
|
6 | "args": [ | |||
|
7 | ], | |||
|
8 | "showOutput": "silent", | |||
|
9 | "tasks": [ | |||
|
10 | { | |||
|
11 | "taskName": "build", | |||
|
12 | // Show the output window only if unrecognized errors occur. | |||
|
13 | "showOutput": "always", | |||
|
14 | // Use the standard MS compiler pattern to detect errors, warnings and infos | |||
|
15 | "problemMatcher": "$msCompile", | |||
|
16 | ||||
|
17 | "args" : [ | |||
|
18 | "/p:Configuration=Debug" | |||
|
19 | ] | |||
|
20 | }, | |||
|
21 | { | |||
|
22 | "taskName": "clean", | |||
|
23 | // Show the output window only if unrecognized errors occur. | |||
|
24 | "showOutput": "always", | |||
|
25 | // Use the standard MS compiler pattern to detect errors, warnings and infos | |||
|
26 | "problemMatcher": "$msCompile" | |||
|
27 | }, | |||
|
28 | { | |||
|
29 | "taskName": "test", | |||
|
30 | "isTestCommand": true, | |||
|
31 | // Show the output window only if unrecognized errors occur. | |||
|
32 | "showOutput": "always", | |||
|
33 | // Use the standard MS compiler pattern to detect errors, warnings and infos | |||
|
34 | "problemMatcher": "$msCompile" | |||
|
35 | } | |||
|
36 | ] | |||
|
37 | } No newline at end of file |
@@ -0,0 +1,6 | |||||
|
1 | <?xml version="1.0" encoding="utf-8"?> | |||
|
2 | <configuration> | |||
|
3 | <startup> | |||
|
4 | <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6"/> | |||
|
5 | </startup> | |||
|
6 | </configuration> |
@@ -0,0 +1,27 | |||||
|
1 | <Project Sdk="Microsoft.NET.Sdk"> | |||
|
2 | <PropertyGroup Condition="'$(OSTYPE)'=='linux'"> | |||
|
3 | <TargetFrameworks>netcoreapp2.0;;net46</TargetFrameworks> | |||
|
4 | <FrameworkPathOverride Condition="'$(TargetFramework)'=='net46'">/usr/lib/mono/4.6-api/</FrameworkPathOverride> | |||
|
5 | </PropertyGroup> | |||
|
6 | ||||
|
7 | <PropertyGroup Condition="'$(OSTYPE)'=='windows'"> | |||
|
8 | <TargetFrameworks>netcoreapp2.0;net46</TargetFrameworks> | |||
|
9 | </PropertyGroup> | |||
|
10 | ||||
|
11 | <PropertyGroup> | |||
|
12 | <OutputType>Exe</OutputType> | |||
|
13 | <IsPackable>false</IsPackable> | |||
|
14 | </PropertyGroup> | |||
|
15 | ||||
|
16 | <ItemGroup> | |||
|
17 | <ProjectReference Include="../Implab/Implab.csproj" /> | |||
|
18 | <ProjectReference Include="..\Implab.ServiceHost\Implab.ServiceHost.csproj" /> | |||
|
19 | </ItemGroup> | |||
|
20 | ||||
|
21 | <ItemGroup> | |||
|
22 | <PackageReference Include="Unity" Version="5.8.6" /> | |||
|
23 | <PackageReference Include="System.Reactive" Version="4.0.0" /> | |||
|
24 | ||||
|
25 | </ItemGroup> | |||
|
26 | ||||
|
27 | </Project> |
@@ -0,0 +1,42 | |||||
|
1 | using System; | |||
|
2 | using System.Collections.Generic; | |||
|
3 | using System.Diagnostics; | |||
|
4 | using System.Dynamic; | |||
|
5 | using System.Linq; | |||
|
6 | using Implab.Components; | |||
|
7 | using Implab.Diagnostics; | |||
|
8 | using Implab.ServiceHost.Unity; | |||
|
9 | using Implab.Xml; | |||
|
10 | using Unity; | |||
|
11 | using Unity.Injection; | |||
|
12 | using Unity.Registration; | |||
|
13 | ||||
|
14 | namespace Implab.Playground { | |||
|
15 | using System.Reactive.Linq; | |||
|
16 | using static Trace<Bar>; | |||
|
17 | ||||
|
18 | class Foo { | |||
|
19 | ||||
|
20 | } | |||
|
21 | ||||
|
22 | class Bar : Foo { | |||
|
23 | ||||
|
24 | } | |||
|
25 | public class Program { | |||
|
26 | ||||
|
27 | static void Main(string[] args) { | |||
|
28 | Trace<Foo>.Log("First!"); | |||
|
29 | Log("+1!"); | |||
|
30 | ||||
|
31 | using(TraceRegistry.Global.OfType<TraceSourceChannel>().Subscribe(ch => { | |||
|
32 | Console.WriteLine($"{ch.Id}: {ch.Source.Name}"); | |||
|
33 | ||||
|
34 | })) { | |||
|
35 | Trace<Foo>.Log("Hi!"); | |||
|
36 | Log("Respect!"); | |||
|
37 | } | |||
|
38 | } | |||
|
39 | ||||
|
40 | ||||
|
41 | } | |||
|
42 | } |
@@ -0,0 +1,74 | |||||
|
1 | <?xml version="1.0" encoding="UTF-8"?> | |||
|
2 | <container xmlns="http://implab.org/schemas/servicehost/unity.v1.xsd"> | |||
|
3 | <namespace name="System"/> | |||
|
4 | <namespace name="System.Collections.Generic"/> | |||
|
5 | <namespace name="Implab.Components"/> | |||
|
6 | <namespace name="Implab.Playground"/> | |||
|
7 | ||||
|
8 | <!-- foo1 --> | |||
|
9 | <register name="foo1" type="Foo"> | |||
|
10 | <property name="Name"> | |||
|
11 | <value>FOO!</value> | |||
|
12 | </property> | |||
|
13 | </register> | |||
|
14 | ||||
|
15 | <!-- foo2 --> | |||
|
16 | <register name="foo2" type="Foo"> | |||
|
17 | <property name="Name"> | |||
|
18 | <value>GOOD</value> | |||
|
19 | </property> | |||
|
20 | <property name="IntValue"> | |||
|
21 | <value>2</value> | |||
|
22 | </property> | |||
|
23 | </register> | |||
|
24 | ||||
|
25 | <register type="Foo"> | |||
|
26 | <method name="AddRange"> | |||
|
27 | <array itemsType="Foo"> | |||
|
28 | <dependency name="foo2"/> | |||
|
29 | </array> | |||
|
30 | </method> | |||
|
31 | </register> | |||
|
32 | ||||
|
33 | <register type="IContainer{}" mapTo="Container{}"> | |||
|
34 | <constructor/> | |||
|
35 | <method name="SetInstance"> | |||
|
36 | <dependency type="T"/> | |||
|
37 | </method> | |||
|
38 | <method name="AddRange"> | |||
|
39 | <array itemsType="T"> | |||
|
40 | <dependency name="foo2-bar"/> | |||
|
41 | </array> | |||
|
42 | </method> | |||
|
43 | </register> | |||
|
44 | ||||
|
45 | <register type="List{}"> | |||
|
46 | <constructor /> | |||
|
47 | </register> | |||
|
48 | ||||
|
49 | <register type="IContainer{String}" mapTo="Container{String}"> | |||
|
50 | <constructor/> | |||
|
51 | <method name="SetInstance"> | |||
|
52 | <dependency type="String" name="name1"/> | |||
|
53 | </method> | |||
|
54 | </register> | |||
|
55 | ||||
|
56 | <serialized type="Foo+Bar"> | |||
|
57 | <Bar xmlns="" id="1"> | |||
|
58 | <Name>Baaar</Name> | |||
|
59 | </Bar> | |||
|
60 | </serialized> | |||
|
61 | ||||
|
62 | <value name="connection1" type="String"><![CDATA[Connect me <here>!]]></value> | |||
|
63 | <value name="name1" type="String" value="Hello!"/> | |||
|
64 | ||||
|
65 | <factory name="foo3" type="IFactory{Foo}" mapTo="FooFactory"> | |||
|
66 | <property name="Connection"> | |||
|
67 | <value><![CDATA[Wired "" objecty <> name @#$%^&]]></value> | |||
|
68 | </property> | |||
|
69 | <property name="UseSsl"> | |||
|
70 | <value>false</value> | |||
|
71 | </property> | |||
|
72 | </factory> | |||
|
73 | ||||
|
74 | </container> No newline at end of file |
@@ -0,0 +1,29 | |||||
|
1 | <Project Sdk="Microsoft.NET.Sdk"> | |||
|
2 | <PropertyGroup Condition="'$(OSTYPE)'=='linux'"> | |||
|
3 | <TargetFrameworks>netcoreapp2.0;net46</TargetFrameworks> | |||
|
4 | <FrameworkPathOverride Condition="'$(TargetFramework)'=='net46'">/usr/lib/mono/4.5/</FrameworkPathOverride> | |||
|
5 | </PropertyGroup> | |||
|
6 | ||||
|
7 | <PropertyGroup Condition="'$(OSTYPE)'=='windows'"> | |||
|
8 | <TargetFrameworks>netcoreapp2.0;net46</TargetFrameworks> | |||
|
9 | </PropertyGroup> | |||
|
10 | ||||
|
11 | <PropertyGroup> | |||
|
12 | <IsPackable>false</IsPackable> | |||
|
13 | </PropertyGroup> | |||
|
14 | ||||
|
15 | <ItemGroup> | |||
|
16 | <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.6.0-preview-20180109-01" /> | |||
|
17 | <PackageReference Include="System.Reactive" Version="4.0.0" /> | |||
|
18 | <PackageReference Include="xunit" Version="2.3.1" /> | |||
|
19 | <PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" /> | |||
|
20 | <ProjectReference Include="../Implab/Implab.csproj"/> | |||
|
21 | <ProjectReference Include="../Implab.ServiceHost/Implab.ServiceHost.csproj"/> | |||
|
22 | <DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" /> | |||
|
23 | </ItemGroup> | |||
|
24 | ||||
|
25 | <ItemGroup> | |||
|
26 | <None Include="data/**/*.*" CopyToOutputDirectory="PreserveNewest" /> | |||
|
27 | </ItemGroup> | |||
|
28 | ||||
|
29 | </Project> |
@@ -0,0 +1,74 | |||||
|
1 | <?xml version="1.0" encoding="UTF-8"?> | |||
|
2 | <container xmlns="http://implab.org/schemas/servicehost/unity.v1.xsd"> | |||
|
3 | <namespace name="System"/> | |||
|
4 | <namespace name="System.Collections.Generic"/> | |||
|
5 | <namespace name="Implab.Components"/> | |||
|
6 | <namespace name="Implab.ServiceHost.Test.Mock"/> | |||
|
7 | ||||
|
8 | <!-- Default FooService --> | |||
|
9 | <register type="FooService{}"> | |||
|
10 | <property name="Name"> | |||
|
11 | <value>I'm default!</value> | |||
|
12 | </property> | |||
|
13 | </register> | |||
|
14 | ||||
|
15 | <!-- foo2 --> | |||
|
16 | <register name="foo2" type="Foo"> | |||
|
17 | <property name="Name"> | |||
|
18 | <value>GOOD</value> | |||
|
19 | </property> | |||
|
20 | <property name="IntValue"> | |||
|
21 | <value>2</value> | |||
|
22 | </property> | |||
|
23 | </register> | |||
|
24 | ||||
|
25 | <register type="Foo"> | |||
|
26 | <method name="AddRange"> | |||
|
27 | <array itemsType="Foo"> | |||
|
28 | <dependency name="foo2"/> | |||
|
29 | </array> | |||
|
30 | </method> | |||
|
31 | </register> | |||
|
32 | ||||
|
33 | <register type="IContainer{}" mapTo="Container{}"> | |||
|
34 | <constructor/> | |||
|
35 | <method name="SetInstance"> | |||
|
36 | <dependency type="T"/> | |||
|
37 | </method> | |||
|
38 | <method name="AddRange"> | |||
|
39 | <array itemsType="T"> | |||
|
40 | <dependency name="foo2-bar"/> | |||
|
41 | </array> | |||
|
42 | </method> | |||
|
43 | </register> | |||
|
44 | ||||
|
45 | <register type="List{}"> | |||
|
46 | <constructor /> | |||
|
47 | </register> | |||
|
48 | ||||
|
49 | <register type="IContainer{String}" mapTo="Container{String}"> | |||
|
50 | <constructor/> | |||
|
51 | <method name="SetInstance"> | |||
|
52 | <dependency type="String" name="name1"/> | |||
|
53 | </method> | |||
|
54 | </register> | |||
|
55 | ||||
|
56 | <serialized type="Foo+Bar"> | |||
|
57 | <Bar xmlns="" id="1"> | |||
|
58 | <Name>Baaar</Name> | |||
|
59 | </Bar> | |||
|
60 | </serialized> | |||
|
61 | ||||
|
62 | <value name="connection1" type="String"><![CDATA[Connect me <here>!]]></value> | |||
|
63 | <value name="name1" type="String" value="Hello!"/> | |||
|
64 | ||||
|
65 | <factory name="foo3" type="IFactory{Foo}" mapTo="FooFactory"> | |||
|
66 | <property name="Connection"> | |||
|
67 | <value><![CDATA[Wired "" objecty <> name @#$%^&]]></value> | |||
|
68 | </property> | |||
|
69 | <property name="UseSsl"> | |||
|
70 | <value>false</value> | |||
|
71 | </property> | |||
|
72 | </factory> | |||
|
73 | ||||
|
74 | </container> No newline at end of file |
@@ -0,0 +1,2 | |||||
|
1 | <container xmlns="http://implab.org/schemas/servicehost/unity.v1.xsd"> | |||
|
2 | </container> No newline at end of file |
@@ -0,0 +1,65 | |||||
|
1 | <?xml version="1.0"?> | |||
|
2 | <container xmlns="http://implab.org/schemas/servicehost/unity.v1.xsd"> | |||
|
3 | <namespace name="System"/> | |||
|
4 | <namespace name="System.Collections.Generic"/> | |||
|
5 | <namespace name="Implab.Components"/> | |||
|
6 | <namespace name="Implab.ServiceHost.Test.Mock"/> | |||
|
7 | ||||
|
8 | <register name="Big" type="Baz+Nut"> | |||
|
9 | <property name="Size"> | |||
|
10 | <value>5</value> | |||
|
11 | </property> | |||
|
12 | </register> | |||
|
13 | <register name="Mid" type="Baz+Nut"> | |||
|
14 | <property name="Size"> | |||
|
15 | <value>3</value> | |||
|
16 | </property> | |||
|
17 | </register> | |||
|
18 | <register name="Small" type="Baz+Nut"> | |||
|
19 | <property name="Size"> | |||
|
20 | <value>1</value> | |||
|
21 | </property> | |||
|
22 | </register> | |||
|
23 | <register type="Baz+Nut"> | |||
|
24 | <property name="Size"> | |||
|
25 | <value>2</value> | |||
|
26 | </property> | |||
|
27 | </register> | |||
|
28 | ||||
|
29 | <!-- register a generic interface mapping to the generic type --> | |||
|
30 | <register type="IBox{}" mapTo="Box{}"> | |||
|
31 | <property name="Value"> | |||
|
32 | <!-- the dependency type is implied from the property and will be the generic parameter {T} --> | |||
|
33 | <dependency optional="true"/> | |||
|
34 | </property> | |||
|
35 | </register> | |||
|
36 | ||||
|
37 | <factory name="Box2" type="BoxFactory{}"> | |||
|
38 | </factory> | |||
|
39 | ||||
|
40 | <register type="IBox{String}" mapTo="Box{String}"> | |||
|
41 | <property name="Name"> | |||
|
42 | <value>boxForString</value> | |||
|
43 | </property> | |||
|
44 | </register> | |||
|
45 | ||||
|
46 | <register name="Small" type="IBox{}" mapTo="Box{}"> | |||
|
47 | <property name="Value"> | |||
|
48 | <dependency name="Small" optional="true"/> | |||
|
49 | </property> | |||
|
50 | </register> | |||
|
51 | ||||
|
52 | <register type="SetOfBoxes{}"> | |||
|
53 | <constructor/> | |||
|
54 | <method name="BoxValues"> | |||
|
55 | <!-- only generic parameter or type without unresolved parameters | |||
|
56 | can be used, this is a limitation of Unity container. TODO --> | |||
|
57 | <array itemsType="T"> | |||
|
58 | <default /> | |||
|
59 | <dependency optional="true"/> | |||
|
60 | <dependency name="Small" optional="true"/> | |||
|
61 | </array> | |||
|
62 | </method> | |||
|
63 | </register> | |||
|
64 | ||||
|
65 | </container> No newline at end of file |
@@ -0,0 +1,6 | |||||
|
1 | <?xml version="1.0"?> | |||
|
2 | <Person xmlns="urn:implab:test:model"> | |||
|
3 | <FirstName>Trohn</FirstName> | |||
|
4 | <LastName>Javolta</LastName> | |||
|
5 | <Age>88</Age> | |||
|
6 | </Person> No newline at end of file |
@@ -0,0 +1,16 | |||||
|
1 | <?xml version="1.0"?> | |||
|
2 | <container xmlns="http://implab.org/schemas/servicehost/unity.v1.xsd"> | |||
|
3 | <namespace name="System"/> | |||
|
4 | <namespace name="System.Collections.Generic"/> | |||
|
5 | <namespace name="Implab.Components"/> | |||
|
6 | <namespace name="Implab.ServiceHost.Test.Mock"/> | |||
|
7 | ||||
|
8 | <serialized name="p1" type="Person"> | |||
|
9 | <Person xmlns="urn:implab:test:model"> | |||
|
10 | <FirstName>Com</FirstName> | |||
|
11 | <LastName>Truise</LastName> | |||
|
12 | <Age>99</Age> | |||
|
13 | </Person> | |||
|
14 | </serialized> | |||
|
15 | <serialized name="p2" type="Person" href="p2.xml"/> | |||
|
16 | </container> No newline at end of file |
@@ -0,0 +1,63 | |||||
|
1 | <?xml version="1.0"?> | |||
|
2 | <container xmlns="http://implab.org/schemas/servicehost/unity.v1.xsd"> | |||
|
3 | <namespace name="System"/> | |||
|
4 | <namespace name="System.Collections.Generic"/> | |||
|
5 | <namespace name="Implab.Components"/> | |||
|
6 | <namespace name="Implab.ServiceHost.Test.Mock"/> | |||
|
7 | ||||
|
8 | <register name="Baz1" type="Baz"> | |||
|
9 | <property name="Numbers"> | |||
|
10 | <array> | |||
|
11 | <value>1</value> | |||
|
12 | <value>2</value> | |||
|
13 | <value>3</value> | |||
|
14 | </array> | |||
|
15 | </property> | |||
|
16 | </register> | |||
|
17 | ||||
|
18 | <register type="Baz"> | |||
|
19 | <property name="Nuts"> | |||
|
20 | <array> | |||
|
21 | <dependency/> | |||
|
22 | <dependency name="Big"/> | |||
|
23 | <dependency name="Big"/> | |||
|
24 | <dependency name="Small"/> | |||
|
25 | <dependency name="Mid"/> | |||
|
26 | </array> | |||
|
27 | </property> | |||
|
28 | </register> | |||
|
29 | ||||
|
30 | <register name="Big" type="Baz+Nut"> | |||
|
31 | <property name="Size"> | |||
|
32 | <value>5</value> | |||
|
33 | </property> | |||
|
34 | </register> | |||
|
35 | <register name="Mid" type="Baz+Nut"> | |||
|
36 | <property name="Size"> | |||
|
37 | <value>3</value> | |||
|
38 | </property> | |||
|
39 | </register> | |||
|
40 | <register name="Small" type="Baz+Nut"> | |||
|
41 | <property name="Size"> | |||
|
42 | <value>1</value> | |||
|
43 | </property> | |||
|
44 | </register> | |||
|
45 | <register type="Baz+Nut"> | |||
|
46 | <property name="Size"> | |||
|
47 | <value>2</value> | |||
|
48 | </property> | |||
|
49 | </register> | |||
|
50 | <factory type="BazFactory"> | |||
|
51 | <provides name="Baz2" type="Baz"/> | |||
|
52 | </factory> | |||
|
53 | ||||
|
54 | <factory name="Baz3" type="BazFactory"> | |||
|
55 | <property name="IdGenerator"> | |||
|
56 | <dependency/> | |||
|
57 | </property> | |||
|
58 | </factory> | |||
|
59 | ||||
|
60 | <factory type="GuidFactory"> | |||
|
61 | <singleton/> | |||
|
62 | </factory> | |||
|
63 | </container> No newline at end of file |
@@ -0,0 +1,23 | |||||
|
1 | using System; | |||
|
2 | using System.Collections.Generic; | |||
|
3 | ||||
|
4 | namespace Implab.ServiceHost.Test.Mock { | |||
|
5 | public class Baz { | |||
|
6 | ||||
|
7 | public Guid Id { | |||
|
8 | get; set; | |||
|
9 | } | |||
|
10 | ||||
|
11 | public int[] Numbers { | |||
|
12 | get; set; | |||
|
13 | } | |||
|
14 | ||||
|
15 | public Nut[] Nuts { | |||
|
16 | get; set; | |||
|
17 | } | |||
|
18 | ||||
|
19 | public class Nut { | |||
|
20 | public int Size { get; set; } | |||
|
21 | } | |||
|
22 | } | |||
|
23 | } No newline at end of file |
@@ -0,0 +1,17 | |||||
|
1 | using System; | |||
|
2 | using Implab.Components; | |||
|
3 | ||||
|
4 | namespace Implab.ServiceHost.Test.Mock { | |||
|
5 | public class BazFactory : IFactory<Baz> { | |||
|
6 | ||||
|
7 | public Func<Guid> IdGenerator { | |||
|
8 | get; set; | |||
|
9 | } | |||
|
10 | ||||
|
11 | Baz IFactory<Baz>.Create() { | |||
|
12 | return new Baz { | |||
|
13 | Id = IdGenerator?.Invoke() ?? Guid.Empty | |||
|
14 | }; | |||
|
15 | } | |||
|
16 | } | |||
|
17 | } No newline at end of file |
@@ -0,0 +1,13 | |||||
|
1 | using System; | |||
|
2 | using Implab.Components; | |||
|
3 | ||||
|
4 | namespace Implab.ServiceHost.Test.Mock { | |||
|
5 | public class BoxFactory<T> : IFactory<IBox<T>> { | |||
|
6 | public IBox<T> Create() { | |||
|
7 | return new Box<T> { | |||
|
8 | Name = "Creepy sugar" | |||
|
9 | }; | |||
|
10 | } | |||
|
11 | } | |||
|
12 | ||||
|
13 | } No newline at end of file |
@@ -0,0 +1,13 | |||||
|
1 | namespace Implab.ServiceHost.Test.Mock { | |||
|
2 | public class Box<T> : IBox<T> { | |||
|
3 | ||||
|
4 | public string Name { get; set; } | |||
|
5 | ||||
|
6 | public T Value { get; set; } | |||
|
7 | ||||
|
8 | public T GetBoxValue() { | |||
|
9 | return Value; | |||
|
10 | } | |||
|
11 | ||||
|
12 | } | |||
|
13 | } No newline at end of file |
@@ -0,0 +1,10 | |||||
|
1 | using System; | |||
|
2 | using Implab.Components; | |||
|
3 | ||||
|
4 | namespace Implab.ServiceHost.Test.Mock { | |||
|
5 | public class GuidFactory : IFactory<Guid> { | |||
|
6 | public Guid Create() { | |||
|
7 | return Guid.NewGuid(); | |||
|
8 | } | |||
|
9 | } | |||
|
10 | } No newline at end of file |
@@ -0,0 +1,6 | |||||
|
1 | namespace Implab.ServiceHost.Test.Mock { | |||
|
2 | public interface IBox<T> { | |||
|
3 | string Name { get; } | |||
|
4 | T GetBoxValue(); | |||
|
5 | } | |||
|
6 | } No newline at end of file |
@@ -0,0 +1,20 | |||||
|
1 | using System.Xml.Serialization; | |||
|
2 | ||||
|
3 | namespace Implab.ServiceHost.Test.Mock | |||
|
4 | { | |||
|
5 | [XmlRoot(Namespace="urn:implab:test:model")] | |||
|
6 | public class Person { | |||
|
7 | public string FirstName { get; set; } | |||
|
8 | ||||
|
9 | public string LastName { get; set; } | |||
|
10 | ||||
|
11 | public int Age { get; set; } | |||
|
12 | ||||
|
13 | [XmlIgnore] | |||
|
14 | public bool AgeSpecified { get; set; } | |||
|
15 | ||||
|
16 | ||||
|
17 | [XmlElement("Tag")] | |||
|
18 | public string[] Tags { get; set; } | |||
|
19 | } | |||
|
20 | } No newline at end of file |
@@ -0,0 +1,21 | |||||
|
1 | using System; | |||
|
2 | using System.Linq; | |||
|
3 | ||||
|
4 | namespace Implab.ServiceHost.Test.Mock { | |||
|
5 | public class SetOfBoxes<T> { | |||
|
6 | ||||
|
7 | public Guid Uuid { get; set; } | |||
|
8 | ||||
|
9 | public IBox<T>[] Boxes { | |||
|
10 | get; set; | |||
|
11 | } | |||
|
12 | ||||
|
13 | public void BoxValues(T[] items) { | |||
|
14 | if (items == null || items.Length == 0) | |||
|
15 | return; | |||
|
16 | ||||
|
17 | Boxes = items.Select(x => new Box<T> {Value = x}).ToArray(); | |||
|
18 | } | |||
|
19 | ||||
|
20 | } | |||
|
21 | } No newline at end of file |
@@ -0,0 +1,94 | |||||
|
1 | using System; | |||
|
2 | using System.Collections.Generic; | |||
|
3 | using System.IO; | |||
|
4 | using System.Linq; | |||
|
5 | using System.Threading; | |||
|
6 | using System.Threading.Tasks; | |||
|
7 | using Implab.Components; | |||
|
8 | using Implab.Diagnostics; | |||
|
9 | using Implab.ServiceHost.Test.Mock; | |||
|
10 | using Implab.ServiceHost.Unity; | |||
|
11 | using Unity; | |||
|
12 | using Xunit; | |||
|
13 | ||||
|
14 | namespace Implab.Test { | |||
|
15 | ||||
|
16 | public class UnityConfigTest { | |||
|
17 | ||||
|
18 | [Fact] | |||
|
19 | public void CreateContainer() { | |||
|
20 | var container = new UnityContainer(); | |||
|
21 | ||||
|
22 | container.LoadXmlConfiguration(Path.Combine("data","container","empty.xml")); | |||
|
23 | } | |||
|
24 | ||||
|
25 | [Fact] | |||
|
26 | public void SimpleServicesContainer() { | |||
|
27 | var container = new UnityContainer(); | |||
|
28 | ||||
|
29 | container.LoadXmlConfiguration(Path.Combine("data","container","simple.services.xml")); | |||
|
30 | ||||
|
31 | // named service registration | |||
|
32 | var baz1 = container.Resolve<Baz>("Baz1"); | |||
|
33 | ||||
|
34 | Assert.Equal(new [] {1,2,3}, baz1.Numbers); | |||
|
35 | ||||
|
36 | // default service registration | |||
|
37 | var baz = container.Resolve<Baz>(); | |||
|
38 | ||||
|
39 | Assert.Equal(new [] {2,5,5,1,3}, baz.Nuts.Select(x => x.Size)); | |||
|
40 | ||||
|
41 | // ServiceFactory registered without a name | |||
|
42 | // explicitly provides 'Baz2' service | |||
|
43 | var baz2 = container.Resolve<Baz>("Baz2"); | |||
|
44 | ||||
|
45 | // ServiceFactory registered with name 'Baz3' | |||
|
46 | // provides by default the service registration with same name | |||
|
47 | var baz3 = container.Resolve<Baz>("Baz3"); | |||
|
48 | ||||
|
49 | // This factory uses GuidGenerator registration | |||
|
50 | // to generate a new id value | |||
|
51 | Assert.NotEqual(Guid.Empty, baz3.Id); | |||
|
52 | } | |||
|
53 | ||||
|
54 | [Fact] | |||
|
55 | public void GenericServicesContainer() { | |||
|
56 | var container = new UnityContainer(); | |||
|
57 | container.LoadXmlConfiguration(Path.Combine("data","container","generic.services.xml")); | |||
|
58 | ||||
|
59 | // resolve using a generig interface mapping | |||
|
60 | var box = container.Resolve<IBox<Baz.Nut>>(); | |||
|
61 | ||||
|
62 | Assert.NotNull(box.GetBoxValue()); | |||
|
63 | ||||
|
64 | // registered generic defines dependency of type {T} | |||
|
65 | // in this case it should resolve to the default Nut with Size=2 | |||
|
66 | Assert.Equal(box.GetBoxValue().Size,2); | |||
|
67 | ||||
|
68 | // generic factory which provides generic services | |||
|
69 | var box2 = container.Resolve<IBox<Baz.Nut>>(); | |||
|
70 | ||||
|
71 | var set1 = container.Resolve<SetOfBoxes<Baz.Nut>>(); | |||
|
72 | ||||
|
73 | Assert.Equal(new int?[] {null,2,1}, set1.Boxes?.Select(x => x.GetBoxValue()?.Size)); | |||
|
74 | } | |||
|
75 | ||||
|
76 | [Fact] | |||
|
77 | public void SerializedInstances() { | |||
|
78 | var container = new UnityContainer(); | |||
|
79 | container.LoadXmlConfiguration(Path.Combine("data","container","serialized.instances.xml")); | |||
|
80 | ||||
|
81 | var p1 = container.Resolve<Person>("p1"); | |||
|
82 | var p2 = container.Resolve<Person>("p2"); | |||
|
83 | ||||
|
84 | Assert.Equal("Com", p1.FirstName); | |||
|
85 | Assert.True(p1.AgeSpecified); | |||
|
86 | Assert.Equal(99, p1.Age); | |||
|
87 | ||||
|
88 | Assert.Equal("Javolta", p2.LastName); | |||
|
89 | Assert.True(p2.AgeSpecified); | |||
|
90 | Assert.Equal(88, p2.Age); | |||
|
91 | } | |||
|
92 | ||||
|
93 | } | |||
|
94 | } No newline at end of file |
@@ -0,0 +1,36 | |||||
|
1 | <Project Sdk="Microsoft.NET.Sdk"> | |||
|
2 | ||||
|
3 | <PropertyGroup> | |||
|
4 | <Authors>Sergey Smirnov</Authors> | |||
|
5 | <Title>Implab.ServiceHost</Title> | |||
|
6 | <Description>The configurable application host. | |||
|
7 | Provides simple and flexible Xml configuration for UnityContainer. | |||
|
8 | </Description> | |||
|
9 | <Copyright>2012-2018 Sergey Smirnov</Copyright> | |||
|
10 | <Version>1.0.3</Version> | |||
|
11 | <PackageLicenseUrl>https://bitbucket.org/wozard/implabnet/src/v3/Implab/license.txt</PackageLicenseUrl> | |||
|
12 | <PackageProjectUrl>https://bitbucket.org/wozard/implabnet</PackageProjectUrl> | |||
|
13 | <RepositoryUrl>https://bitbucket.org/wozard/implabnet</RepositoryUrl> | |||
|
14 | <RepositoryType>mercurial</RepositoryType> | |||
|
15 | <PackageTags>Implab;Xml configuration;IoC;Unity container</PackageTags> | |||
|
16 | </PropertyGroup> | |||
|
17 | ||||
|
18 | ||||
|
19 | <PropertyGroup Condition="'$(OSTYPE)'=='linux'"> | |||
|
20 | <TargetFrameworks>netcoreapp2.0;net46</TargetFrameworks> | |||
|
21 | <FrameworkPathOverride Condition="'$(TargetFramework)'=='net46'">/usr/lib/mono/4.5/</FrameworkPathOverride> | |||
|
22 | </PropertyGroup> | |||
|
23 | ||||
|
24 | <PropertyGroup Condition="'$(OSTYPE)'=='windows'"> | |||
|
25 | <TargetFrameworks>netcoreapp2.0;net46</TargetFrameworks> | |||
|
26 | </PropertyGroup> | |||
|
27 | ||||
|
28 | <ItemGroup> | |||
|
29 | <PackageReference Include="Unity" Version="5.8.6" /> | |||
|
30 | </ItemGroup> | |||
|
31 | ||||
|
32 | <ItemGroup> | |||
|
33 | <ProjectReference Include="..\Implab\Implab.csproj" /> | |||
|
34 | </ItemGroup> | |||
|
35 | ||||
|
36 | </Project> |
@@ -0,0 +1,113 | |||||
|
1 | # XML Конфигурация IoC контейнера | |||
|
2 | ||||
|
3 | Библиоетка создавалась для загрузки и применения конфигурации к IoC контейнеру, она не предназначена для конфигурирования | |||
|
4 | контейнера во время выполнения, большинство контейнеров уже обладают данным функционалом. | |||
|
5 | ||||
|
6 | На данный момент поддерживается единственный вид контейнера - [Unity Container](https://unitycontainer.github.io/) | |||
|
7 | ||||
|
8 | Unity уже обладает средствами загрузки конфигурации из XML, данная библиотека реализует аналогичный функционал, кроме того, позволяет решать следующие задачи: | |||
|
9 | ||||
|
10 | - Конфигурация является простым Xml документом, который можно получить из любого источика и не ограничивается `.config` файлами приложения | |||
|
11 | - Включение существующе конфигурации `<include href='config.xml'/>` в текущую | |||
|
12 | - Поддержка сериализованных объектов в качестве регистраций сервисов и параметров | |||
|
13 | - Поддержка специфиакции генериков любой вложенности, например `Dictionary{Foo,Bar{Int32}}` | |||
|
14 | - Поддержка фабрик в XML конфигурации | |||
|
15 | - Расширение схемы XML конфигурации собственными элементами | |||
|
16 | ||||
|
17 | ## Общая архитектура | |||
|
18 | ||||
|
19 | Пространство имен `Implab.ServiceHost.Unity` содержит в себе классы для загрузки и применения XML конфигурации к IoC контейнеру. | |||
|
20 | ||||
|
21 | Применение конфигурации к контейнеру состоит из следующих основных шагов: | |||
|
22 | ||||
|
23 | 1. Настраивается схема `ContainerConfigurationSchema` XML конфигурации контейнера | |||
|
24 | 2. Загружается документ и десереализуется в виде `ContainerElement` | |||
|
25 | 3. Создается `ContainerBuilder` при помощи которого применяются настройки из `ContainerElement` к контейнеру | |||
|
26 | ||||
|
27 | Схема `ContainerConfigurationSchema` определяет элементы документа, которые могут быть использованы в конфигурации контейнера, позволяет создать `XmlSerializer`, который используется для загрузки конфигурации. | |||
|
28 | ||||
|
29 | `ContainerBuilder` - основной класс, который используется для применения конфигурации к контейнеру, он добавляет записи регистрации сервисов из конфигурации в контейнер. | |||
|
30 | ||||
|
31 | `ContainerElement` - Конфигурация контейнера, которая загружается из документа, состоит из директив для `ContainerBuilder`, а также из записей регистрации сервисов. | |||
|
32 | ||||
|
33 | В библиотеки приняты следующие правила именования классов: | |||
|
34 | ||||
|
35 | - `***Builder` используются для применения конфигурации к контейнеру, | |||
|
36 | - `***Element` содержат информацию о конфигурации и десериализуются из исходного документа. | |||
|
37 | ||||
|
38 | ## Структура конфигурации контейнера | |||
|
39 | ||||
|
40 | Элемент верхнего уровня всегда `container`, он используется для хранения набора элеметов, которые распознаются и выполняются `ContainerBuilder`. | |||
|
41 | ||||
|
42 | Все элементы, входящие в контейнер наследуются от абстрактного класса `ContainerItemElement`, | |||
|
43 | который позволяет получить текущий `ContainerBuilder` и выполнить над ним какие-либо действия. | |||
|
44 | ||||
|
45 | Основные элементы конфигурации контенейра | |||
|
46 | ||||
|
47 | - `<include href='config.xml'/>` - включение конфигурации из указанного места | |||
|
48 | - `<namespace name='My.App'/>` - добавление пространства имен для поиска типов | |||
|
49 | - `<register type='MyGenericType{}'/>` - добавление в контейнер регистрации типа ``My.App.MyGenericType`1`` | |||
|
50 | - `<factory type='IFactory{Foo}' mapTo ='MyFactory'/>` - фабрика, регистрирует свой тип, а также тип `Foo` | |||
|
51 | - `<serialized />` - сериализованный экземпляр объекта, использует `XmlSerializer` для десериализации | |||
|
52 | - `<value />` - значение объекта в виде строки, используется для простых типов | |||
|
53 | ||||
|
54 | Полный набор элементов, доступных для использования в контейнере определяет схема `ContainerConfigurationSchema`, | |||
|
55 | разработчик может расширить контейнер совими собственными элементами зарегистрировав их в схеме. | |||
|
56 | ||||
|
57 | ### register | |||
|
58 | ||||
|
59 | О | |||
|
60 | ||||
|
61 | ||||
|
62 | Например, мы используем компоненту `MyHttpClient` для загрузки данных | |||
|
63 | ||||
|
64 | ```xml | |||
|
65 | <register type="IClient" mapTo="MyHttpClient"> | |||
|
66 | <property name="proxy"> | |||
|
67 | <value>socks5://proxy1.my.company</value> | |||
|
68 | </property> | |||
|
69 | </register> | |||
|
70 | ``` | |||
|
71 | ||||
|
72 | При частом использовании можно сделать описание конфигурации несколько проще, | |||
|
73 | описав новый эелемент конфигурации | |||
|
74 | ||||
|
75 | ```csharp | |||
|
76 | public class MyHttpClientElement : ContainerItemElement { | |||
|
77 | ||||
|
78 | public string Proxy { get; set; } | |||
|
79 | ||||
|
80 | public override void Visit(ContainerBuilder builder) { | |||
|
81 | // создаем описание элемента | |||
|
82 | var registration = new RegistrationElement { | |||
|
83 | RegistrationType = "IClient", | |||
|
84 | ImplementationType = "My.App.MyHttpClient", | |||
|
85 | Injectors = new [] { | |||
|
86 | new PropertyInjectionElement { | |||
|
87 | Name = "Proxy", | |||
|
88 | Value = ValueParameterElement { | |||
|
89 | Value = Proxy | |||
|
90 | } | |||
|
91 | } | |||
|
92 | } | |||
|
93 | }; | |||
|
94 | ||||
|
95 | // применяем созданное описание к контейнеру | |||
|
96 | builder.Visit(registration) | |||
|
97 | } | |||
|
98 | } | |||
|
99 | ``` | |||
|
100 | ||||
|
101 | Регистрируем новый элемент в схеме | |||
|
102 | ||||
|
103 | ```csharp | |||
|
104 | schema.RegisterContainerElement<MyHttpClientElement>("http"); | |||
|
105 | ``` | |||
|
106 | ||||
|
107 | Используем новый элемент в конфигурации | |||
|
108 | ||||
|
109 | ```xml | |||
|
110 | <http> | |||
|
111 | <proxy>socks5://proxy1.my.company</propxy> | |||
|
112 | </http> | |||
|
113 | ``` No newline at end of file |
@@ -0,0 +1,12 | |||||
|
1 | namespace Implab.ServiceHost.Unity { | |||
|
2 | ||||
|
3 | /// <summary> | |||
|
4 | /// Базовый класс для элеметов контейнера. | |||
|
5 | /// </summary> | |||
|
6 | /// <remarks> | |||
|
7 | /// XmlSerializer требует использования классов при объявлении свойств, которые будут сериализованы <see cref="ContainerElement.Items"/> | |||
|
8 | /// </remarks> | |||
|
9 | public abstract class AbstractContainerItem { | |||
|
10 | public abstract void Visit(ContainerBuilder builder); | |||
|
11 | } | |||
|
12 | } No newline at end of file |
@@ -0,0 +1,12 | |||||
|
1 | using System; | |||
|
2 | using System.Xml.Serialization; | |||
|
3 | ||||
|
4 | namespace Implab.ServiceHost.Unity { | |||
|
5 | public abstract class AbstractInjectionParameter : IInjectionParameter { | |||
|
6 | ||||
|
7 | [XmlAttribute("type")] | |||
|
8 | public string TypeName { get; set; } | |||
|
9 | ||||
|
10 | public abstract void Visit(InjectionParameterBuilder builder); | |||
|
11 | } | |||
|
12 | } No newline at end of file |
@@ -0,0 +1,10 | |||||
|
1 | using System; | |||
|
2 | ||||
|
3 | namespace Implab.ServiceHost.Unity { | |||
|
4 | /// <summary> | |||
|
5 | /// Base class for injections, each injection is applied to the type registration context. | |||
|
6 | /// </summary> | |||
|
7 | public abstract class AbstractMemberInjection : ITypeMemberInjection { | |||
|
8 | public abstract void Visit(TypeRegistrationBuilder builder); | |||
|
9 | } | |||
|
10 | } No newline at end of file |
@@ -0,0 +1,48 | |||||
|
1 | using System; | |||
|
2 | using System.Xml.Serialization; | |||
|
3 | using Unity.Lifetime; | |||
|
4 | using Unity.Registration; | |||
|
5 | ||||
|
6 | namespace Implab.ServiceHost.Unity | |||
|
7 | { | |||
|
8 | /// <summary> | |||
|
9 | /// Базовая информаци о регистрации в контейнере: тип, имя и время жизни | |||
|
10 | /// </summary> | |||
|
11 | public abstract class AbstractRegistration : AbstractContainerItem, IRegistration { | |||
|
12 | ||||
|
13 | /// <summary> | |||
|
14 | /// An optional name for a registration in the container | |||
|
15 | /// </summary> | |||
|
16 | [XmlAttribute("name")] | |||
|
17 | public string Name { | |||
|
18 | get; set; | |||
|
19 | } | |||
|
20 | ||||
|
21 | [XmlElement("signleton", typeof(SingletonLifetimeElement))] | |||
|
22 | [XmlElement("context", typeof(ContextLifetimeElement))] | |||
|
23 | [XmlElement("container", typeof(ContainerLifetimeElement))] | |||
|
24 | [XmlElement("hierarchy", typeof(HierarchicalLifetimeElement))] | |||
|
25 | public LifetimeElement Lifetime {get; set;} | |||
|
26 | ||||
|
27 | /// <summary> | |||
|
28 | /// A type specification for the service registration, | |||
|
29 | /// </summary> | |||
|
30 | [XmlAttribute("type")] | |||
|
31 | public string RegistrationType { get; set; } | |||
|
32 | ||||
|
33 | public virtual LifetimeManager GetLifetime(ContainerBuilder builder) { | |||
|
34 | return Lifetime?.GetLifetime(builder); | |||
|
35 | } | |||
|
36 | ||||
|
37 | public virtual Type GetRegistrationType(Func<string,Type> resolver) { | |||
|
38 | return resolver(RegistrationType); | |||
|
39 | } | |||
|
40 | ||||
|
41 | public virtual Type GetRegistrationType(ContainerBuilder builder) { | |||
|
42 | return builder.ResolveType(RegistrationType); | |||
|
43 | } | |||
|
44 | ||||
|
45 | ||||
|
46 | ||||
|
47 | } | |||
|
48 | } No newline at end of file |
@@ -0,0 +1,20 | |||||
|
1 | using System.Xml.Serialization; | |||
|
2 | ||||
|
3 | namespace Implab.ServiceHost.Unity | |||
|
4 | { | |||
|
5 | public class ArrayParameterElement : AbstractInjectionParameter { | |||
|
6 | ||||
|
7 | [XmlAttribute("itemsType")] | |||
|
8 | public string ItemsType { get; set; } | |||
|
9 | ||||
|
10 | [XmlElement("dependency", typeof(DependencyParameterElement))] | |||
|
11 | [XmlElement("value", typeof(ValueParameterElement))] | |||
|
12 | [XmlElement("serialized", typeof(SerializedParameterElement))] | |||
|
13 | [XmlElement("default", typeof(DefaultParameterElement))] | |||
|
14 | public AbstractInjectionParameter[] Items { get; set; } | |||
|
15 | ||||
|
16 | public override void Visit(InjectionParameterBuilder builder) { | |||
|
17 | builder.Visit(this); | |||
|
18 | } | |||
|
19 | } | |||
|
20 | } No newline at end of file |
@@ -0,0 +1,57 | |||||
|
1 | using System; | |||
|
2 | using System.Text; | |||
|
3 | ||||
|
4 | namespace Implab.ServiceHost.Unity { | |||
|
5 | public class ArrayTypeReference : TypeReference { | |||
|
6 | public int Rank { get; private set; } | |||
|
7 | ||||
|
8 | public TypeReference ItemsType { get; private set; } | |||
|
9 | ||||
|
10 | public override string Name { | |||
|
11 | get { | |||
|
12 | return ItemsType.Name; | |||
|
13 | } | |||
|
14 | } | |||
|
15 | ||||
|
16 | public override string ClrName { | |||
|
17 | get { | |||
|
18 | return new StringBuilder() | |||
|
19 | .Append(ItemsType.ClrName) | |||
|
20 | .Append("[") | |||
|
21 | .Append(',', Rank - 1) | |||
|
22 | .Append("]") | |||
|
23 | .ToString(); | |||
|
24 | } | |||
|
25 | } | |||
|
26 | ||||
|
27 | public override string Namespace { | |||
|
28 | get { | |||
|
29 | return ItemsType.Namespace; | |||
|
30 | } | |||
|
31 | } | |||
|
32 | ||||
|
33 | public override int GenericParametersCount { | |||
|
34 | get { | |||
|
35 | return 0; | |||
|
36 | } | |||
|
37 | } | |||
|
38 | ||||
|
39 | internal ArrayTypeReference(TypeReference itemsType, int rank) { | |||
|
40 | ItemsType = itemsType; | |||
|
41 | Rank = rank; | |||
|
42 | } | |||
|
43 | ||||
|
44 | internal override void Visit(TypeResolutionContext visitor) { | |||
|
45 | visitor.Visit(this); | |||
|
46 | } | |||
|
47 | ||||
|
48 | override public string ToString() { | |||
|
49 | return new StringBuilder() | |||
|
50 | .Append(ItemsType.ToString()) | |||
|
51 | .Append('[') | |||
|
52 | .Append(',', Rank - 1) | |||
|
53 | .Append(']') | |||
|
54 | .ToString(); | |||
|
55 | } | |||
|
56 | } | |||
|
57 | } No newline at end of file |
@@ -0,0 +1,14 | |||||
|
1 | using System.Xml.Serialization; | |||
|
2 | ||||
|
3 | namespace Implab.ServiceHost.Unity | |||
|
4 | { | |||
|
5 | [XmlRoot("assembly", Namespace = Schema.ContainerConfigurationNamespace)] | |||
|
6 | public class AssemblyElement : AbstractContainerItem { | |||
|
7 | [XmlAttribute("name")] | |||
|
8 | public string AssemblyName { get; set; } | |||
|
9 | ||||
|
10 | public override void Visit(ContainerBuilder builder) { | |||
|
11 | builder.AddAssembly(AssemblyName); | |||
|
12 | } | |||
|
13 | } | |||
|
14 | } No newline at end of file |
@@ -0,0 +1,17 | |||||
|
1 | using System.Xml.Serialization; | |||
|
2 | ||||
|
3 | namespace Implab.ServiceHost.Unity { | |||
|
4 | public class ConstructorInjectionElement : AbstractMemberInjection { | |||
|
5 | ||||
|
6 | [XmlElement("dependency", typeof(DependencyParameterElement))] | |||
|
7 | [XmlElement("value", typeof(ValueParameterElement))] | |||
|
8 | [XmlElement("serialized", typeof(SerializedParameterElement))] | |||
|
9 | [XmlElement("default", typeof(DefaultParameterElement))] | |||
|
10 | [XmlElement("array", typeof(ArrayParameterElement))] | |||
|
11 | public AbstractInjectionParameter[] Parameters { get; set; } | |||
|
12 | ||||
|
13 | public override void Visit(TypeRegistrationBuilder builder) { | |||
|
14 | builder.Visit(this); | |||
|
15 | } | |||
|
16 | } | |||
|
17 | } No newline at end of file |
@@ -0,0 +1,161 | |||||
|
1 | using System; | |||
|
2 | using System.IO; | |||
|
3 | using System.Reflection; | |||
|
4 | using Implab.Diagnostics; | |||
|
5 | using Unity; | |||
|
6 | ||||
|
7 | namespace Implab.ServiceHost.Unity { | |||
|
8 | using Log = Trace<ContainerBuilder>; | |||
|
9 | ||||
|
10 | public class ContainerBuilder { | |||
|
11 | ||||
|
12 | readonly TypeResolver m_resolver; | |||
|
13 | ||||
|
14 | readonly IUnityContainer m_container; | |||
|
15 | ||||
|
16 | readonly ContainerConfigurationSchema m_schema; | |||
|
17 | ||||
|
18 | Uri m_location; | |||
|
19 | ||||
|
20 | public IUnityContainer Container { | |||
|
21 | get { | |||
|
22 | return m_container; | |||
|
23 | } | |||
|
24 | } | |||
|
25 | ||||
|
26 | public ContainerBuilder() : this(null, null) { | |||
|
27 | } | |||
|
28 | ||||
|
29 | public ContainerBuilder(IUnityContainer container, ContainerConfigurationSchema schema) { | |||
|
30 | m_container = container ?? new UnityContainer(); | |||
|
31 | m_resolver = new TypeResolver(); | |||
|
32 | m_schema = schema ?? ContainerConfigurationSchema.Default; | |||
|
33 | } | |||
|
34 | ||||
|
35 | public Type ResolveType(string typeReference) { | |||
|
36 | var resolved = string.IsNullOrEmpty(typeReference) ? null : m_resolver.Resolve(typeReference, true); | |||
|
37 | Log.Debug("ResolveType('{0}'): {1}", typeReference, resolved?.FullName); | |||
|
38 | return resolved; | |||
|
39 | } | |||
|
40 | ||||
|
41 | public void Visit(ITypeRegistration registration) { | |||
|
42 | Safe.ArgumentNotNull(registration, nameof(registration)); | |||
|
43 | ||||
|
44 | var registrationType = registration.GetRegistrationType(this); | |||
|
45 | var implementationType = registration.GetImplementationType(this) ?? registrationType; | |||
|
46 | ||||
|
47 | if (registrationType == null) | |||
|
48 | throw new Exception($"A type must be specified for the registration {registration.Name}"); | |||
|
49 | ||||
|
50 | var builder = new TypeRegistrationBuilder( | |||
|
51 | m_resolver, | |||
|
52 | registrationType, | |||
|
53 | implementationType, | |||
|
54 | this | |||
|
55 | ); | |||
|
56 | ||||
|
57 | builder.Lifetime = registration.GetLifetime(this); | |||
|
58 | ||||
|
59 | if (registration.MemberInjections != null) { | |||
|
60 | foreach(var member in registration.MemberInjections) | |||
|
61 | member.Visit(builder); | |||
|
62 | } | |||
|
63 | ||||
|
64 | m_container.RegisterType( | |||
|
65 | builder.RegistrationType, | |||
|
66 | builder.ImplementationType, | |||
|
67 | registration.Name, | |||
|
68 | builder.Lifetime, | |||
|
69 | builder.Injections | |||
|
70 | ); | |||
|
71 | } | |||
|
72 | ||||
|
73 | public void Visit(IInstanceRegistration registration) { | |||
|
74 | Safe.ArgumentNotNull(registration, nameof(registration)); | |||
|
75 | ||||
|
76 | var registrationType = registration.GetRegistrationType(this); | |||
|
77 | ||||
|
78 | var builder = new InstanceRegistrationBuilder ( | |||
|
79 | m_resolver, | |||
|
80 | registrationType, | |||
|
81 | this | |||
|
82 | ); | |||
|
83 | ||||
|
84 | builder.Lifetime = registration.GetLifetime(this); | |||
|
85 | ||||
|
86 | if (registration.MemberInjections != null) { | |||
|
87 | foreach(var member in registration.MemberInjections) | |||
|
88 | member.Visit(builder.ValueBuilder); | |||
|
89 | } | |||
|
90 | ||||
|
91 | if (builder.RegistrationType == null && builder.ValueBuilder.ValueType == null) | |||
|
92 | throw new Exception($"A type must be specified for the registration {registration.Name}"); | |||
|
93 | ||||
|
94 | m_container.RegisterInstance( | |||
|
95 | builder.RegistrationType ?? builder.ValueBuilder.ValueType, | |||
|
96 | registration.Name, | |||
|
97 | builder.ValueBuilder.Value, | |||
|
98 | builder.Lifetime | |||
|
99 | ); | |||
|
100 | } | |||
|
101 | ||||
|
102 | public void AddNamespace(string ns) { | |||
|
103 | m_resolver.AddNamespace(ns); | |||
|
104 | Log.Log($"AddNamespace: {ns}"); | |||
|
105 | } | |||
|
106 | ||||
|
107 | public void AddAssembly(string assembly) { | |||
|
108 | var asm = Assembly.Load(assembly); | |||
|
109 | Log.Log($"AddAssembly: {assembly} -> {asm.FullName}"); | |||
|
110 | } | |||
|
111 | ||||
|
112 | /// <summary> | |||
|
113 | /// Includes the confguration. Creates a new <see cref="ContainerBuilder"/>, | |||
|
114 | /// and loads the configuration to it. The created builder will share the | |||
|
115 | /// container and will have its own isolated type resolver. | |||
|
116 | /// </summary> | |||
|
117 | /// <param name="file">A path to configuration relative to the current configuration.</param> | |||
|
118 | public void Include(string file) { | |||
|
119 | var includeContext = new ContainerBuilder(m_container, m_schema); | |||
|
120 | ||||
|
121 | if (m_location != null) { | |||
|
122 | var uri = new Uri(m_location, file); | |||
|
123 | includeContext.LoadConfig(uri); | |||
|
124 | } else { | |||
|
125 | includeContext.LoadConfig(file); | |||
|
126 | } | |||
|
127 | } | |||
|
128 | ||||
|
129 | /// <summary> | |||
|
130 | /// Resolves a path ralatively to the current container configuration location. | |||
|
131 | /// </summary> | |||
|
132 | /// <param name="location">A path yto resolve</param> | |||
|
133 | /// <returns>Resolved Uri fot the specified location</returns> | |||
|
134 | public Uri MakeLocationUri(string location) { | |||
|
135 | return m_location != null ? new Uri(m_location, location) : new Uri(location); | |||
|
136 | } | |||
|
137 | ||||
|
138 | /// <summary> | |||
|
139 | /// Loads a configuration from the specified local file. | |||
|
140 | /// </summary> | |||
|
141 | /// <param name="file">The path to the configuration file.</param> | |||
|
142 | public void LoadConfig(string file) { | |||
|
143 | Safe.ArgumentNotEmpty(file, nameof(file)); | |||
|
144 | ||||
|
145 | LoadConfig(new Uri(Path.GetFullPath(file))); | |||
|
146 | } | |||
|
147 | ||||
|
148 | public void LoadConfig(Uri location) { | |||
|
149 | Safe.ArgumentNotNull(location, nameof(location)); | |||
|
150 | ||||
|
151 | Log.Log($"LoadConfig {location}"); | |||
|
152 | Safe.ArgumentNotNull(location, nameof(location)); | |||
|
153 | ||||
|
154 | m_location = location; | |||
|
155 | ||||
|
156 | var config = m_schema.LoadConfig(location.ToString()); | |||
|
157 | config.Visit(this); | |||
|
158 | } | |||
|
159 | ||||
|
160 | } | |||
|
161 | } No newline at end of file |
@@ -0,0 +1,70 | |||||
|
1 | using System; | |||
|
2 | using System.Collections.Generic; | |||
|
3 | using System.IO; | |||
|
4 | using System.Reflection; | |||
|
5 | using System.Xml; | |||
|
6 | using System.Xml.Serialization; | |||
|
7 | using Implab.Components; | |||
|
8 | ||||
|
9 | namespace Implab.ServiceHost.Unity { | |||
|
10 | public class ContainerConfigurationSchema { | |||
|
11 | ||||
|
12 | public static ContainerConfigurationSchema Default { get; private set; } = CreateDefault(); | |||
|
13 | ||||
|
14 | readonly LazyAndWeak<XmlSerializer> m_seralizer; | |||
|
15 | ||||
|
16 | readonly XmlAttributeOverrides m_overrides = new XmlAttributeOverrides(); | |||
|
17 | ||||
|
18 | readonly XmlAttributes m_containerItems = new XmlAttributes(); | |||
|
19 | ||||
|
20 | public XmlSerializer Serializer { | |||
|
21 | get { | |||
|
22 | return m_seralizer.Value; | |||
|
23 | } | |||
|
24 | } | |||
|
25 | ||||
|
26 | public ContainerConfigurationSchema() { | |||
|
27 | m_overrides.Add(typeof(ContainerElement), nameof(ContainerElement.Items), m_containerItems); | |||
|
28 | ||||
|
29 | m_seralizer = new LazyAndWeak<XmlSerializer>(() => new XmlSerializer(typeof(ContainerElement), m_overrides)); | |||
|
30 | } | |||
|
31 | ||||
|
32 | public void RegisterContainerElement(Type type, string name) { | |||
|
33 | Safe.ArgumentNotNull(type, nameof(type)); | |||
|
34 | Safe.ArgumentNotEmpty(name, nameof(name)); | |||
|
35 | ||||
|
36 | if(!type.IsSubclassOf(typeof(AbstractContainerItem))) | |||
|
37 | throw new Exception($"RegisterContainerElement '{name}': {type} must be subclass of {typeof(AbstractContainerItem)}"); | |||
|
38 | ||||
|
39 | m_containerItems.XmlElements.Add( | |||
|
40 | new XmlElementAttribute(name, type) | |||
|
41 | ); | |||
|
42 | } | |||
|
43 | ||||
|
44 | public void RegisterContainerElement<T>(string name) where T : AbstractContainerItem { | |||
|
45 | RegisterContainerElement(typeof(T), name); | |||
|
46 | } | |||
|
47 | ||||
|
48 | public ContainerElement LoadConfig(string uri) { | |||
|
49 | using (var reader = XmlReader.Create(uri)) { | |||
|
50 | return (ContainerElement)Serializer.Deserialize(reader); | |||
|
51 | } | |||
|
52 | } | |||
|
53 | ||||
|
54 | static ContainerConfigurationSchema CreateDefault() { | |||
|
55 | var schema = new ContainerConfigurationSchema(); | |||
|
56 | ||||
|
57 | schema.RegisterContainerElement<RegisterElement>("register"); | |||
|
58 | schema.RegisterContainerElement<FactoryElement>("factory"); | |||
|
59 | schema.RegisterContainerElement<SerializedElement>("serialized"); | |||
|
60 | schema.RegisterContainerElement<ValueElement>("value"); | |||
|
61 | schema.RegisterContainerElement<IncludeElement>("include"); | |||
|
62 | schema.RegisterContainerElement<AssemblyElement>("assembly"); | |||
|
63 | schema.RegisterContainerElement<NamespaceElement>("namespace"); | |||
|
64 | ||||
|
65 | return schema; | |||
|
66 | } | |||
|
67 | ||||
|
68 | ||||
|
69 | } | |||
|
70 | } No newline at end of file |
@@ -0,0 +1,19 | |||||
|
1 | using Implab.Xml; | |||
|
2 | using System.Collections.Generic; | |||
|
3 | using System.Xml; | |||
|
4 | using System.Xml.Schema; | |||
|
5 | using System.Xml.Serialization; | |||
|
6 | ||||
|
7 | namespace Implab.ServiceHost.Unity { | |||
|
8 | [XmlRoot("container", Namespace = Schema.ContainerConfigurationNamespace)] | |||
|
9 | public class ContainerElement : AbstractContainerItem { | |||
|
10 | ||||
|
11 | public List<AbstractContainerItem> Items { get; set; } = new List<AbstractContainerItem>(); | |||
|
12 | ||||
|
13 | public override void Visit(ContainerBuilder context) { | |||
|
14 | if (Items != null) | |||
|
15 | foreach(var item in Items) | |||
|
16 | item.Visit(context); | |||
|
17 | } | |||
|
18 | } | |||
|
19 | } No newline at end of file |
@@ -0,0 +1,12 | |||||
|
1 | using Unity.Lifetime; | |||
|
2 | ||||
|
3 | namespace Implab.ServiceHost.Unity | |||
|
4 | { | |||
|
5 | public class ContainerLifetimeElement : LifetimeElement { | |||
|
6 | public override LifetimeManager GetLifetime(ContainerBuilder builder) { | |||
|
7 | return new ContainerControlledLifetimeManager(); | |||
|
8 | } | |||
|
9 | ||||
|
10 | ||||
|
11 | } | |||
|
12 | } No newline at end of file |
@@ -0,0 +1,10 | |||||
|
1 | using Unity.Lifetime; | |||
|
2 | ||||
|
3 | namespace Implab.ServiceHost.Unity | |||
|
4 | { | |||
|
5 | public class ContextLifetimeElement : LifetimeElement { | |||
|
6 | public override LifetimeManager GetLifetime(ContainerBuilder builder) { | |||
|
7 | return new PerResolveLifetimeManager(); | |||
|
8 | } | |||
|
9 | } | |||
|
10 | } No newline at end of file |
@@ -0,0 +1,13 | |||||
|
1 | namespace Implab.ServiceHost.Unity | |||
|
2 | { | |||
|
3 | public class DefaultParameterElement : AbstractInjectionParameter { | |||
|
4 | public string Value { | |||
|
5 | get { return null; } | |||
|
6 | } | |||
|
7 | ||||
|
8 | public override void Visit(InjectionParameterBuilder builder) { | |||
|
9 | var type = builder.ResolveInjectedValueType(TypeName); | |||
|
10 | builder.SetValue(type, Safe.CreateDefaultValue(type)); | |||
|
11 | } | |||
|
12 | } | |||
|
13 | } No newline at end of file |
@@ -0,0 +1,17 | |||||
|
1 | using System.Xml.Serialization; | |||
|
2 | ||||
|
3 | namespace Implab.ServiceHost.Unity { | |||
|
4 | public class DependencyParameterElement : AbstractInjectionParameter { | |||
|
5 | ||||
|
6 | [XmlAttribute("name")] | |||
|
7 | public string DependencyName { get; set; } | |||
|
8 | ||||
|
9 | [XmlAttribute("optional")] | |||
|
10 | public bool Optional { get; set; } | |||
|
11 | ||||
|
12 | public override void Visit(InjectionParameterBuilder builder) { | |||
|
13 | var type = builder.ResolveInjectedValueType(TypeName); | |||
|
14 | builder.SetDependency(type, DependencyName, Optional); | |||
|
15 | } | |||
|
16 | } | |||
|
17 | } No newline at end of file |
@@ -0,0 +1,78 | |||||
|
1 | using System; | |||
|
2 | using System.Collections.Generic; | |||
|
3 | using System.Reflection; | |||
|
4 | using Implab.Components; | |||
|
5 | using Unity; | |||
|
6 | using Unity.Injection; | |||
|
7 | using Unity.Lifetime; | |||
|
8 | ||||
|
9 | namespace Implab.ServiceHost.Unity { | |||
|
10 | public class FactoryActivator : ITypeRegistration { | |||
|
11 | ||||
|
12 | class FactoryInjector : ITypeMemberInjection { | |||
|
13 | public InjectionFactory Factory { get; set; } | |||
|
14 | public void Visit(TypeRegistrationBuilder builder) { | |||
|
15 | builder.AddInjectionMember(Factory); | |||
|
16 | } | |||
|
17 | } | |||
|
18 | ||||
|
19 | ||||
|
20 | public Type FactoryType { get; set; } | |||
|
21 | ||||
|
22 | public string FactoryName { get; set; } | |||
|
23 | ||||
|
24 | public Type RegistrationType { get; set; } | |||
|
25 | ||||
|
26 | public LifetimeManager Lifetime { get; set; } | |||
|
27 | ||||
|
28 | public IEnumerable<ITypeMemberInjection> MemberInjections { | |||
|
29 | get { | |||
|
30 | if (RegistrationType == null) | |||
|
31 | throw new Exception($"RegistrationType must be specified"); | |||
|
32 | if (!typeof(IFactory<>).MakeGenericType(RegistrationType).IsAssignableFrom(FactoryType)) | |||
|
33 | throw new Exception($"The factory {FactoryType} can't be used to create {RegistrationType} instances"); | |||
|
34 | ||||
|
35 | if (FactoryType.ContainsGenericParameters) { | |||
|
36 | yield return new FactoryInjector { | |||
|
37 | Factory = CreateDynamicInjectionFactory(FactoryName) | |||
|
38 | }; | |||
|
39 | } else { | |||
|
40 | yield return new FactoryInjector { | |||
|
41 | Factory = (InjectionFactory)GetType() | |||
|
42 | .GetMethod(nameof(CreateInjectionFactory), BindingFlags.Static | BindingFlags.NonPublic) | |||
|
43 | .MakeGenericMethod(FactoryType, RegistrationType) | |||
|
44 | .Invoke(null, new [] { FactoryName }) | |||
|
45 | }; | |||
|
46 | } | |||
|
47 | } | |||
|
48 | } | |||
|
49 | ||||
|
50 | public string Name { get; set; } | |||
|
51 | ||||
|
52 | public Type GetRegistrationType(ContainerBuilder builder) { | |||
|
53 | return RegistrationType; | |||
|
54 | } | |||
|
55 | ||||
|
56 | public LifetimeManager GetLifetime(ContainerBuilder builder) { | |||
|
57 | return Lifetime; | |||
|
58 | } | |||
|
59 | ||||
|
60 | public Type GetImplementationType(ContainerBuilder builder) { | |||
|
61 | return null; | |||
|
62 | } | |||
|
63 | ||||
|
64 | /// <summary> | |||
|
65 | /// Указывает зависимость, реализующую интерфейс <see cref="IFactory{TObj}"/>, | |||
|
66 | /// которая будет использоваться в качестве фабрики для создания объектов | |||
|
67 | /// </summary> | |||
|
68 | /// <param name="dependencyName"></param> | |||
|
69 | static InjectionFactory CreateInjectionFactory<TFac, TObj>(string dependencyName) where TFac : IFactory<TObj> { | |||
|
70 | ||||
|
71 | return new InjectionFactory(c => c.Resolve<TFac>(dependencyName).Create()); | |||
|
72 | } | |||
|
73 | ||||
|
74 | static InjectionFactory CreateDynamicInjectionFactory(string dependencyName) { | |||
|
75 | return new InjectionFactory((c,t,name) => ((IFactory<object>)c.Resolve(t, dependencyName)).Create()); | |||
|
76 | } | |||
|
77 | } | |||
|
78 | } No newline at end of file |
@@ -0,0 +1,73 | |||||
|
1 | using System; | |||
|
2 | using System.Xml.Serialization; | |||
|
3 | using Implab.Components; | |||
|
4 | ||||
|
5 | namespace Implab.ServiceHost.Unity { | |||
|
6 | /// <summary> | |||
|
7 | /// Расширяет стандартную регистрацию типа до фабрики, вместе с регистрацией | |||
|
8 | /// самой фабрики создаются регистрации сервисов, которые она предоставляет. | |||
|
9 | /// </summary> | |||
|
10 | public class FactoryElement : RegisterElement, ITypeRegistration { | |||
|
11 | ||||
|
12 | /// <summary> | |||
|
13 | /// Записи о сервисах, которые создаются данной фабрикой. | |||
|
14 | /// </summary> | |||
|
15 | /// <remarks> | |||
|
16 | /// Сервисы, которые указаны в регистарциях они должны соответсвовать тому, | |||
|
17 | /// что фабрика возвращает, но это остается на откуп контейнера | |||
|
18 | /// </remarks> | |||
|
19 | [XmlElement("provides")] | |||
|
20 | public ProvidesElement[] Provides { get; set; } | |||
|
21 | ||||
|
22 | /// <summary> | |||
|
23 | /// Переопределяет стандарное поведение регистрации типа в контейнере, | |||
|
24 | /// дополняя его регистрацией фабричных методов для получения типов. | |||
|
25 | /// </summary> | |||
|
26 | /// <param name="builder">Объект для конфигурирования контейнера.</param> | |||
|
27 | public override void Visit(ContainerBuilder builder) { | |||
|
28 | var factoryType = GetRegistrationType(builder.ResolveType); | |||
|
29 | ||||
|
30 | base.Visit(builder); | |||
|
31 | ||||
|
32 | if (Provides != null && Provides.Length > 0) { | |||
|
33 | // если регистрации явно заданы, используеися информация из них | |||
|
34 | foreach(var item in Provides) { | |||
|
35 | var activator = new FactoryActivator { | |||
|
36 | Name = item.RegistrationName, | |||
|
37 | RegistrationType = builder.ResolveType(item.RegistrationType), | |||
|
38 | FactoryName = Name, | |||
|
39 | FactoryType = factoryType, | |||
|
40 | Lifetime = item.Lifetime?.GetLifetime(builder) | |||
|
41 | }; | |||
|
42 | builder.Visit(activator); | |||
|
43 | } | |||
|
44 | } else { | |||
|
45 | // если регистрация явно не задана, в качестве сервиса для регистрации | |||
|
46 | // используется тип создаваемый фабрикой, который будет добавлен в контейнер | |||
|
47 | // с темже именем, что и сама фабрика (разные типы могут иметь одно имя для регистрации) | |||
|
48 | var providedType = ( | |||
|
49 | factoryType.IsGenericType && factoryType.GetGenericTypeDefinition() == typeof(IFactory<>) ? | |||
|
50 | factoryType : | |||
|
51 | factoryType.GetInterface(typeof(IFactory<>).FullName) | |||
|
52 | )? | |||
|
53 | .GetGenericArguments()[0]; | |||
|
54 | ||||
|
55 | // не удалось определеить тип | |||
|
56 | if (providedType == null) | |||
|
57 | throw new ArgumentException("Failed to determine a type provided by the factory"); | |||
|
58 | ||||
|
59 | if (providedType.IsGenericParameter) | |||
|
60 | throw new ArgumentException("Can't register a generic type paramter as a service"); | |||
|
61 | ||||
|
62 | var activator = new FactoryActivator { | |||
|
63 | Name = Name, | |||
|
64 | RegistrationType = providedType, | |||
|
65 | FactoryName = Name, | |||
|
66 | FactoryType = factoryType | |||
|
67 | }; | |||
|
68 | ||||
|
69 | builder.Visit(activator); | |||
|
70 | } | |||
|
71 | } | |||
|
72 | } | |||
|
73 | } No newline at end of file |
@@ -0,0 +1,10 | |||||
|
1 | using Unity.Lifetime; | |||
|
2 | ||||
|
3 | namespace Implab.ServiceHost.Unity | |||
|
4 | { | |||
|
5 | public class HierarchicalLifetimeElement : LifetimeElement { | |||
|
6 | public override LifetimeManager GetLifetime(ContainerBuilder builder) { | |||
|
7 | return new HierarchicalLifetimeManager(); | |||
|
8 | } | |||
|
9 | } | |||
|
10 | } No newline at end of file |
@@ -0,0 +1,5 | |||||
|
1 | namespace Implab.ServiceHost.Unity { | |||
|
2 | public interface IInjectionParameter { | |||
|
3 | void Visit(InjectionParameterBuilder builder); | |||
|
4 | } | |||
|
5 | } No newline at end of file |
@@ -0,0 +1,8 | |||||
|
1 | using System.Collections.Generic; | |||
|
2 | ||||
|
3 | namespace Implab.ServiceHost.Unity { | |||
|
4 | public interface IInstanceRegistration : IRegistration { | |||
|
5 | ||||
|
6 | IEnumerable<IInjectionParameter> MemberInjections { get; } | |||
|
7 | } | |||
|
8 | } No newline at end of file |
@@ -0,0 +1,12 | |||||
|
1 | using System; | |||
|
2 | using Unity.Lifetime; | |||
|
3 | ||||
|
4 | namespace Implab.ServiceHost.Unity { | |||
|
5 | public interface IRegistration { | |||
|
6 | string Name { get; } | |||
|
7 | ||||
|
8 | Type GetRegistrationType(ContainerBuilder builder); | |||
|
9 | ||||
|
10 | LifetimeManager GetLifetime(ContainerBuilder builder); | |||
|
11 | } | |||
|
12 | } No newline at end of file |
@@ -0,0 +1,6 | |||||
|
1 | namespace Implab.ServiceHost.Unity | |||
|
2 | { | |||
|
3 | public interface ITypeMemberInjection { | |||
|
4 | void Visit(TypeRegistrationBuilder builder); | |||
|
5 | } | |||
|
6 | } No newline at end of file |
@@ -0,0 +1,10 | |||||
|
1 | using System; | |||
|
2 | using System.Collections.Generic; | |||
|
3 | ||||
|
4 | namespace Implab.ServiceHost.Unity { | |||
|
5 | public interface ITypeRegistration : IRegistration { | |||
|
6 | Type GetImplementationType(ContainerBuilder builder); | |||
|
7 | ||||
|
8 | IEnumerable<ITypeMemberInjection> MemberInjections { get; } | |||
|
9 | } | |||
|
10 | } No newline at end of file |
@@ -0,0 +1,13 | |||||
|
1 | using System.Xml.Serialization; | |||
|
2 | ||||
|
3 | namespace Implab.ServiceHost.Unity { | |||
|
4 | [XmlRoot("include", Namespace = Schema.ContainerConfigurationNamespace)] | |||
|
5 | public class IncludeElement : AbstractContainerItem { | |||
|
6 | [XmlAttribute("href")] | |||
|
7 | public string Href { get; set; } | |||
|
8 | ||||
|
9 | public override void Visit(ContainerBuilder builder) { | |||
|
10 | builder.Include(Href); | |||
|
11 | } | |||
|
12 | } | |||
|
13 | } No newline at end of file |
@@ -0,0 +1,142 | |||||
|
1 | using System; | |||
|
2 | using System.Collections; | |||
|
3 | using System.Collections.Generic; | |||
|
4 | using System.ComponentModel; | |||
|
5 | using System.Linq; | |||
|
6 | using System.Xml.Serialization; | |||
|
7 | using Unity.Injection; | |||
|
8 | ||||
|
9 | namespace Implab.ServiceHost.Unity { | |||
|
10 | ||||
|
11 | public class InjectionParameterBuilder { | |||
|
12 | ||||
|
13 | readonly TypeResolver m_resolver; | |||
|
14 | ||||
|
15 | public Type DefaultType { get; private set; } | |||
|
16 | ||||
|
17 | public Type ValueType { get; private set; } | |||
|
18 | ||||
|
19 | public ContainerBuilder Root { get; private set; } | |||
|
20 | ||||
|
21 | object m_value; | |||
|
22 | ||||
|
23 | public object Value { | |||
|
24 | get { | |||
|
25 | if (!ValueSpecified) | |||
|
26 | throw new InvalidOperationException("The regular value must be set (dependency or array are not situable in this context)"); | |||
|
27 | return m_value; | |||
|
28 | } | |||
|
29 | } | |||
|
30 | ||||
|
31 | public bool ValueSpecified { get; private set; } | |||
|
32 | ||||
|
33 | InjectionParameterValue m_injection; | |||
|
34 | ||||
|
35 | public InjectionParameterValue Injection { | |||
|
36 | get { | |||
|
37 | if (m_injection == null) | |||
|
38 | throw new InvalidOperationException("The injection parameter is not specified"); | |||
|
39 | return m_injection; | |||
|
40 | } | |||
|
41 | } | |||
|
42 | ||||
|
43 | public bool InjectionSpecified { | |||
|
44 | get { return m_injection != null; } | |||
|
45 | } | |||
|
46 | ||||
|
47 | internal InjectionParameterBuilder(TypeResolver resolver, Type defaultType, ContainerBuilder root) { | |||
|
48 | m_resolver = resolver; | |||
|
49 | DefaultType = defaultType; | |||
|
50 | Root = root; | |||
|
51 | } | |||
|
52 | ||||
|
53 | public Type ResolveInjectedValueType(string typeSpec) { | |||
|
54 | if (string.IsNullOrEmpty(typeSpec)) { | |||
|
55 | if (DefaultType == null) | |||
|
56 | throw new Exception("The type must be specified"); | |||
|
57 | return DefaultType; | |||
|
58 | } | |||
|
59 | return m_resolver.Resolve(typeSpec, true); | |||
|
60 | } | |||
|
61 | ||||
|
62 | public Type ResolveType(string typeSpec) { | |||
|
63 | return string.IsNullOrEmpty(typeSpec) ? null : m_resolver.Resolve(typeSpec, true); | |||
|
64 | } | |||
|
65 | ||||
|
66 | public void SetValue(Type type, object value) { | |||
|
67 | Safe.ArgumentNotNull(type, nameof(type)); | |||
|
68 | ||||
|
69 | ValueType = type; | |||
|
70 | m_value = value; | |||
|
71 | ValueSpecified = true; | |||
|
72 | ||||
|
73 | m_injection = new InjectionParameter(type, value); | |||
|
74 | } | |||
|
75 | ||||
|
76 | public void SetDependency(Type type, string name, bool optional) { | |||
|
77 | Safe.ArgumentNotNull(type, nameof(type)); | |||
|
78 | ||||
|
79 | ValueType = type; | |||
|
80 | ValueSpecified = false; | |||
|
81 | m_value = null; | |||
|
82 | ||||
|
83 | m_injection = optional ? | |||
|
84 | type.IsGenericParameter ? | |||
|
85 | new OptionalGenericParameter(type.Name, name) | |||
|
86 | : (InjectionParameterValue)new OptionalParameter(type, name) | |||
|
87 | : new ResolvedParameter(type, name); | |||
|
88 | } | |||
|
89 | ||||
|
90 | internal void Visit(ArrayParameterElement arrayParameter) { | |||
|
91 | Type itemsType = null; | |||
|
92 | var arrayType = string.IsNullOrEmpty(arrayParameter.TypeName) ? null : ResolveType(arrayParameter.TypeName); | |||
|
93 | ||||
|
94 | if (arrayType == null) | |||
|
95 | arrayType = DefaultType; | |||
|
96 | ||||
|
97 | ||||
|
98 | if (!string.IsNullOrEmpty(arrayParameter.ItemsType)) { | |||
|
99 | itemsType = ResolveType(arrayParameter.ItemsType); | |||
|
100 | arrayType = itemsType.MakeArrayType(); | |||
|
101 | } else { | |||
|
102 | itemsType = GetItemsType(arrayType); | |||
|
103 | } | |||
|
104 | ||||
|
105 | if (itemsType == null) | |||
|
106 | throw new Exception("Failed to determine array elements type"); | |||
|
107 | ||||
|
108 | InjectionParameterValue[] injections = (arrayParameter.Items ?? new AbstractInjectionParameter[0]) | |||
|
109 | .Select(x => { | |||
|
110 | var builder = new InjectionParameterBuilder(m_resolver, itemsType, Root); | |||
|
111 | x.Visit(builder); | |||
|
112 | return builder.Injection; | |||
|
113 | }) | |||
|
114 | .ToArray(); | |||
|
115 | ||||
|
116 | m_injection = itemsType.IsGenericParameter ? | |||
|
117 | (InjectionParameterValue)new GenericResolvedArrayParameter(itemsType.Name, injections) : | |||
|
118 | new ResolvedArrayParameter(itemsType, injections); | |||
|
119 | ||||
|
120 | ValueType = arrayType; | |||
|
121 | m_value = null; | |||
|
122 | ValueSpecified = false; | |||
|
123 | } | |||
|
124 | ||||
|
125 | Type GetItemsType(Type collectionType) { | |||
|
126 | if (collectionType == null) | |||
|
127 | return null; | |||
|
128 | ||||
|
129 | Type itemsType = null; | |||
|
130 | ||||
|
131 | if (collectionType.IsGenericType && collectionType.GetGenericTypeDefinition() == typeof(IEnumerable<>)) { | |||
|
132 | itemsType = collectionType.GetGenericArguments()[0]; | |||
|
133 | } else if (collectionType == typeof(IEnumerable)) { | |||
|
134 | itemsType = typeof(object); | |||
|
135 | } else { | |||
|
136 | itemsType = collectionType.GetInterface(typeof(IEnumerable<>).FullName)?.GetGenericArguments()[0]; | |||
|
137 | } | |||
|
138 | ||||
|
139 | return itemsType; | |||
|
140 | } | |||
|
141 | } | |||
|
142 | } No newline at end of file |
@@ -0,0 +1,13 | |||||
|
1 | using System; | |||
|
2 | ||||
|
3 | namespace Implab.ServiceHost.Unity | |||
|
4 | { | |||
|
5 | public class InstanceRegistrationBuilder : RegistrationBuilder { | |||
|
6 | ||||
|
7 | public InjectionParameterBuilder ValueBuilder { get; private set; } | |||
|
8 | ||||
|
9 | internal InstanceRegistrationBuilder(TypeResolver typeResolver, Type registrationType, ContainerBuilder root) : base(registrationType, root) { | |||
|
10 | ValueBuilder = new InjectionParameterBuilder(typeResolver, registrationType, root); | |||
|
11 | } | |||
|
12 | } | |||
|
13 | } No newline at end of file |
@@ -0,0 +1,7 | |||||
|
1 | using Unity.Lifetime; | |||
|
2 | ||||
|
3 | namespace Implab.ServiceHost.Unity { | |||
|
4 | public abstract class LifetimeElement { | |||
|
5 | public abstract LifetimeManager GetLifetime(ContainerBuilder builder); | |||
|
6 | } | |||
|
7 | } No newline at end of file |
@@ -0,0 +1,20 | |||||
|
1 | using System.Xml.Serialization; | |||
|
2 | ||||
|
3 | namespace Implab.ServiceHost.Unity { | |||
|
4 | public class MethodInjectionElement : AbstractMemberInjection { | |||
|
5 | ||||
|
6 | [XmlAttribute("name")] | |||
|
7 | public string Name { get; set; } | |||
|
8 | ||||
|
9 | [XmlElement("dependency", typeof(DependencyParameterElement))] | |||
|
10 | [XmlElement("value", typeof(ValueParameterElement))] | |||
|
11 | [XmlElement("serialized", typeof(SerializedParameterElement))] | |||
|
12 | [XmlElement("default", typeof(DefaultParameterElement))] | |||
|
13 | [XmlElement("array", typeof(ArrayParameterElement))] | |||
|
14 | public AbstractInjectionParameter[] Parameters { get; set; } | |||
|
15 | ||||
|
16 | public override void Visit(TypeRegistrationBuilder context) { | |||
|
17 | context.Visit(this); | |||
|
18 | } | |||
|
19 | } | |||
|
20 | } No newline at end of file |
@@ -0,0 +1,15 | |||||
|
1 | using System.Xml.Serialization; | |||
|
2 | ||||
|
3 | namespace Implab.ServiceHost.Unity | |||
|
4 | { | |||
|
5 | [XmlRoot("namespace", Namespace = Schema.ContainerConfigurationNamespace)] | |||
|
6 | public class NamespaceElement : AbstractContainerItem { | |||
|
7 | ||||
|
8 | [XmlAttribute("name")] | |||
|
9 | public string Name { get; set; } | |||
|
10 | ||||
|
11 | public override void Visit(ContainerBuilder builder) { | |||
|
12 | builder.AddNamespace(Name); | |||
|
13 | } | |||
|
14 | } | |||
|
15 | } No newline at end of file |
@@ -0,0 +1,48 | |||||
|
1 | using System; | |||
|
2 | using System.Text; | |||
|
3 | ||||
|
4 | namespace Implab.ServiceHost.Unity { | |||
|
5 | public class NestedTypeReference : TypeReference { | |||
|
6 | ||||
|
7 | readonly string m_name; | |||
|
8 | ||||
|
9 | readonly int m_genericParametersCount; | |||
|
10 | ||||
|
11 | public TypeReference DeclaringType { get; private set; } | |||
|
12 | ||||
|
13 | public override string Name { | |||
|
14 | get { | |||
|
15 | return m_name; | |||
|
16 | } | |||
|
17 | } | |||
|
18 | ||||
|
19 | public override string Namespace { | |||
|
20 | get { | |||
|
21 | return DeclaringType.Namespace; | |||
|
22 | } | |||
|
23 | } | |||
|
24 | ||||
|
25 | public override int GenericParametersCount { | |||
|
26 | get { | |||
|
27 | return m_genericParametersCount; | |||
|
28 | } | |||
|
29 | } | |||
|
30 | ||||
|
31 | internal NestedTypeReference(TypeReference declaringType, string name, int parametersCount) { | |||
|
32 | DeclaringType = declaringType; | |||
|
33 | m_name = name; | |||
|
34 | m_genericParametersCount = parametersCount; | |||
|
35 | } | |||
|
36 | ||||
|
37 | internal override void Visit(TypeResolutionContext visitor) { | |||
|
38 | visitor.Visit(this); | |||
|
39 | } | |||
|
40 | ||||
|
41 | internal override void WriteTypeName(StringBuilder builder) { | |||
|
42 | builder | |||
|
43 | .Append(DeclaringType) | |||
|
44 | .Append('+') | |||
|
45 | .Append(Name); | |||
|
46 | } | |||
|
47 | } | |||
|
48 | } No newline at end of file |
@@ -0,0 +1,20 | |||||
|
1 | using System.Xml.Serialization; | |||
|
2 | ||||
|
3 | namespace Implab.ServiceHost.Unity { | |||
|
4 | public class PropertyInjectionElement : AbstractMemberInjection { | |||
|
5 | ||||
|
6 | [XmlAttribute("name")] | |||
|
7 | public string Name { get; set; } | |||
|
8 | ||||
|
9 | [XmlElement("dependency", typeof(DependencyParameterElement))] | |||
|
10 | [XmlElement("value", typeof(ValueParameterElement))] | |||
|
11 | [XmlElement("serialized", typeof(SerializedParameterElement))] | |||
|
12 | [XmlElement("default", typeof(DefaultParameterElement))] | |||
|
13 | [XmlElement("array", typeof(ArrayParameterElement))] | |||
|
14 | public AbstractInjectionParameter Value { get; set; } | |||
|
15 | ||||
|
16 | public override void Visit(TypeRegistrationBuilder context) { | |||
|
17 | context.Visit(this); | |||
|
18 | } | |||
|
19 | } | |||
|
20 | } No newline at end of file |
@@ -0,0 +1,17 | |||||
|
1 | using System.Xml.Serialization; | |||
|
2 | ||||
|
3 | namespace Implab.ServiceHost.Unity { | |||
|
4 | public class ProvidesElement { | |||
|
5 | [XmlAttribute("type")] | |||
|
6 | public string RegistrationType { get; set; } | |||
|
7 | ||||
|
8 | [XmlAttribute("name")] | |||
|
9 | public string RegistrationName { get; set; } | |||
|
10 | ||||
|
11 | [XmlElement("signleton", typeof(SingletonLifetimeElement))] | |||
|
12 | [XmlElement("context", typeof(ContextLifetimeElement))] | |||
|
13 | [XmlElement("container", typeof(ContainerLifetimeElement))] | |||
|
14 | [XmlElement("hierarchy", typeof(HierarchicalLifetimeElement))] | |||
|
15 | public LifetimeElement Lifetime {get; set;} | |||
|
16 | } | |||
|
17 | } No newline at end of file |
@@ -0,0 +1,39 | |||||
|
1 | using System; | |||
|
2 | using System.Collections.Generic; | |||
|
3 | using System.Xml.Serialization; | |||
|
4 | using Unity.Lifetime; | |||
|
5 | using Unity.Registration; | |||
|
6 | ||||
|
7 | namespace Implab.ServiceHost.Unity { | |||
|
8 | ||||
|
9 | [XmlRoot("register", Namespace = Schema.ContainerConfigurationNamespace)] | |||
|
10 | public class RegisterElement : AbstractRegistration, ITypeRegistration { | |||
|
11 | ||||
|
12 | /// <summary> | |||
|
13 | /// An optional type which is registered as a service in the container, must be assignable to <see cref="ProvidesType">. | |||
|
14 | /// </summary> | |||
|
15 | [XmlAttribute("mapTo")] | |||
|
16 | public string MapToType { get; set; } | |||
|
17 | ||||
|
18 | ||||
|
19 | [XmlElement("constructor", typeof(ConstructorInjectionElement))] | |||
|
20 | [XmlElement("property", typeof(PropertyInjectionElement))] | |||
|
21 | [XmlElement("method", typeof(MethodInjectionElement))] | |||
|
22 | public AbstractMemberInjection[] Injectors { get; set; } | |||
|
23 | ||||
|
24 | IEnumerable<ITypeMemberInjection> ITypeRegistration.MemberInjections { | |||
|
25 | get { | |||
|
26 | return Injectors; | |||
|
27 | } | |||
|
28 | } | |||
|
29 | ||||
|
30 | public Type GetImplementationType(ContainerBuilder builder) { | |||
|
31 | return builder.ResolveType(MapToType); | |||
|
32 | } | |||
|
33 | ||||
|
34 | public override void Visit(ContainerBuilder builder) { | |||
|
35 | builder.Visit(this); | |||
|
36 | } | |||
|
37 | } | |||
|
38 | ||||
|
39 | } No newline at end of file |
@@ -0,0 +1,32 | |||||
|
1 | using System; | |||
|
2 | using System.Collections.Generic; | |||
|
3 | using System.ComponentModel; | |||
|
4 | using System.Linq; | |||
|
5 | using System.Xml.Serialization; | |||
|
6 | using Implab.Xml; | |||
|
7 | using Unity.Injection; | |||
|
8 | using Unity.Lifetime; | |||
|
9 | using Unity.Registration; | |||
|
10 | ||||
|
11 | namespace Implab.ServiceHost.Unity { | |||
|
12 | /// <summary> | |||
|
13 | /// Базовый класс для формирования записей в контейнере, созволяет указать время жизни для записи | |||
|
14 | /// </summary> | |||
|
15 | public abstract class RegistrationBuilder { | |||
|
16 | public ContainerBuilder Root { | |||
|
17 | get; private set; | |||
|
18 | } | |||
|
19 | ||||
|
20 | public Type RegistrationType { | |||
|
21 | get; | |||
|
22 | private set; | |||
|
23 | } | |||
|
24 | ||||
|
25 | internal LifetimeManager Lifetime { get; set; } | |||
|
26 | ||||
|
27 | protected RegistrationBuilder(Type registrationType, ContainerBuilder root) { | |||
|
28 | Root = root; | |||
|
29 | RegistrationType = registrationType; | |||
|
30 | } | |||
|
31 | } | |||
|
32 | } No newline at end of file |
@@ -0,0 +1,36 | |||||
|
1 | using System; | |||
|
2 | ||||
|
3 | namespace Implab.ServiceHost.Unity | |||
|
4 | { | |||
|
5 | public class RootTypeReference : TypeReference { | |||
|
6 | readonly string m_name; | |||
|
7 | ||||
|
8 | readonly string m_namespace; | |||
|
9 | ||||
|
10 | readonly int m_genericParametersCount; | |||
|
11 | ||||
|
12 | public override string Name { | |||
|
13 | get { return m_name; } | |||
|
14 | } | |||
|
15 | ||||
|
16 | public override string Namespace { | |||
|
17 | get { return m_namespace; } | |||
|
18 | } | |||
|
19 | ||||
|
20 | public override int GenericParametersCount { | |||
|
21 | get { return m_genericParametersCount; } | |||
|
22 | } | |||
|
23 | ||||
|
24 | internal RootTypeReference(string ns, string name, int genericParameters) { | |||
|
25 | m_name = name; | |||
|
26 | m_genericParametersCount = genericParameters; | |||
|
27 | m_namespace = ns; | |||
|
28 | } | |||
|
29 | ||||
|
30 | internal override void Visit(TypeResolutionContext visitor) { | |||
|
31 | visitor.Visit(this); | |||
|
32 | } | |||
|
33 | ||||
|
34 | ||||
|
35 | } | |||
|
36 | } No newline at end of file |
@@ -0,0 +1,5 | |||||
|
1 | namespace Implab.ServiceHost.Unity { | |||
|
2 | public static class Schema { | |||
|
3 | public const string ContainerConfigurationNamespace = "http://implab.org/schemas/servicehost/unity.v1.xsd"; | |||
|
4 | } | |||
|
5 | } No newline at end of file |
@@ -0,0 +1,32 | |||||
|
1 | using System; | |||
|
2 | using System.Collections.Generic; | |||
|
3 | using System.Xml; | |||
|
4 | using System.Xml.Serialization; | |||
|
5 | ||||
|
6 | namespace Implab.ServiceHost.Unity { | |||
|
7 | public class SerializedElement : AbstractRegistration, IInstanceRegistration { | |||
|
8 | [XmlAttribute("href")] | |||
|
9 | public string Location { get; set; } | |||
|
10 | ||||
|
11 | [XmlAttribute("serializedType")] | |||
|
12 | public string SerializedType { get; set; } | |||
|
13 | ||||
|
14 | ||||
|
15 | [XmlAnyElement] | |||
|
16 | public XmlElement[] Content { get; set; } | |||
|
17 | ||||
|
18 | public IEnumerable<IInjectionParameter> MemberInjections { | |||
|
19 | get { | |||
|
20 | yield return new SerializedParameterElement { | |||
|
21 | TypeName = SerializedType, | |||
|
22 | Location = Location, | |||
|
23 | Content = Content | |||
|
24 | }; | |||
|
25 | } | |||
|
26 | } | |||
|
27 | ||||
|
28 | public override void Visit(ContainerBuilder builder) { | |||
|
29 | builder.Visit(this); | |||
|
30 | } | |||
|
31 | } | |||
|
32 | } No newline at end of file |
@@ -0,0 +1,33 | |||||
|
1 | using System; | |||
|
2 | using System.Xml; | |||
|
3 | using System.Xml.Schema; | |||
|
4 | using System.Xml.Serialization; | |||
|
5 | ||||
|
6 | namespace Implab.ServiceHost.Unity | |||
|
7 | { | |||
|
8 | public class SerializedParameterElement : AbstractInjectionParameter { | |||
|
9 | [XmlAttribute("href")] | |||
|
10 | public string Location { get; set; } | |||
|
11 | ||||
|
12 | [XmlAnyElement] | |||
|
13 | public XmlElement[] Content { get; set; } | |||
|
14 | ||||
|
15 | public XmlReader GetReader(InjectionParameterBuilder builder) { | |||
|
16 | if (!string.IsNullOrEmpty(Location)) | |||
|
17 | return XmlReader.Create(builder.Root.MakeLocationUri(Location).ToString()); | |||
|
18 | if (Content != null && Content.Length > 0) | |||
|
19 | return Content[0].CreateNavigator().ReadSubtree(); | |||
|
20 | ||||
|
21 | throw new Exception("No content found, expected XML document"); | |||
|
22 | } | |||
|
23 | ||||
|
24 | public override void Visit(InjectionParameterBuilder builder) { | |||
|
25 | var type = builder.ResolveInjectedValueType(TypeName); | |||
|
26 | ||||
|
27 | var serializer = new XmlSerializer(type); | |||
|
28 | using(var reader = GetReader(builder)) | |||
|
29 | builder.SetValue(type, serializer.Deserialize(reader)); | |||
|
30 | ||||
|
31 | } | |||
|
32 | } | |||
|
33 | } No newline at end of file |
@@ -0,0 +1,10 | |||||
|
1 | using Unity.Lifetime; | |||
|
2 | ||||
|
3 | namespace Implab.ServiceHost.Unity | |||
|
4 | { | |||
|
5 | public class SingletonLifetimeElement : LifetimeElement { | |||
|
6 | public override LifetimeManager GetLifetime(ContainerBuilder builder) { | |||
|
7 | return new SingletonLifetimeManager(); | |||
|
8 | } | |||
|
9 | } | |||
|
10 | } No newline at end of file |
@@ -0,0 +1,52 | |||||
|
1 | using System; | |||
|
2 | using System.Linq; | |||
|
3 | using System.Text; | |||
|
4 | ||||
|
5 | namespace Implab.ServiceHost.Unity { | |||
|
6 | public class SpecializedTypeReference : TypeReference { | |||
|
7 | public override string Name { | |||
|
8 | get { | |||
|
9 | return GenericType.Name; | |||
|
10 | } | |||
|
11 | } | |||
|
12 | ||||
|
13 | public override string Namespace { | |||
|
14 | get { | |||
|
15 | return GenericType.Namespace; | |||
|
16 | } | |||
|
17 | } | |||
|
18 | ||||
|
19 | public override int GenericParametersCount { | |||
|
20 | get { | |||
|
21 | return GenericParameters.Length; | |||
|
22 | } | |||
|
23 | } | |||
|
24 | ||||
|
25 | public TypeReference GenericType { get; private set; } | |||
|
26 | ||||
|
27 | public TypeReference[] GenericParameters { get; private set; } | |||
|
28 | ||||
|
29 | internal SpecializedTypeReference(TypeReference genericType, TypeReference[] genericParameters) { | |||
|
30 | GenericType = genericType; | |||
|
31 | GenericParameters = genericParameters; | |||
|
32 | } | |||
|
33 | ||||
|
34 | internal override void Visit(TypeResolutionContext visitor) { | |||
|
35 | visitor.Visit(this); | |||
|
36 | } | |||
|
37 | ||||
|
38 | internal override void WriteTypeName(StringBuilder builder) { | |||
|
39 | GenericType.WriteTypeName(builder); | |||
|
40 | } | |||
|
41 | ||||
|
42 | internal override void WriteTypeParams(StringBuilder builder) { | |||
|
43 | builder.Append('{'); | |||
|
44 | for (var i = 0; i < GenericParameters.Length; i++) { | |||
|
45 | if (i > 0) | |||
|
46 | builder.Append(','); | |||
|
47 | builder.Append(GenericParameters[i]); | |||
|
48 | } | |||
|
49 | builder.Append('}'); | |||
|
50 | } | |||
|
51 | } | |||
|
52 | } No newline at end of file |
@@ -0,0 +1,182 | |||||
|
1 | using System; | |||
|
2 | using System.Linq; | |||
|
3 | using System.Text; | |||
|
4 | ||||
|
5 | namespace Implab.ServiceHost.Unity { | |||
|
6 | /// <summary> | |||
|
7 | /// Ссылка на тип, является абстрактной записью имени CLR типа. | |||
|
8 | /// </summary> | |||
|
9 | /// <remarks> | |||
|
10 | /// Ссылка на тип содержит сокращенную информацию о типе и для ее интерпретации | |||
|
11 | /// требуется некоторый контекст, который позволит превратить ее в полноценный | |||
|
12 | /// <see cref="Type"/>. Ссылки на тип позволяют записать: | |||
|
13 | /// <list> | |||
|
14 | /// <item><description>общие типы, их специализации</description></item> | |||
|
15 | /// <item><description>вложенные типы</description></item> | |||
|
16 | /// <item><description>массивы</description></item> | |||
|
17 | /// </list> | |||
|
18 | /// <para> | |||
|
19 | /// Для получения из ссылки на тип конкретного CLR типа используется <see cref="TypeResolver.Resolve(TypeReference, bool)"/>. | |||
|
20 | /// </para> | |||
|
21 | /// <para> | |||
|
22 | /// Ссылку на тип можно создать либо програмно при помощи методов <see cref="Create(string, string, int)"/>, | |||
|
23 | /// <see cref="Create(string, int)"/>, <see cref="MakeArrayType(int)"/>, <see cref="MakeGenericType(TypeReference[])"/>, | |||
|
24 | /// либо разобрав строку со спецификацией при помощи метода <see cref="Parse(string)"/>. | |||
|
25 | /// </para> | |||
|
26 | /// <para> | |||
|
27 | /// Спецификация ссыдки на тип имеет следующий вид <c>Name.Space.MyType+Nested{String}[][]</c>, где: | |||
|
28 | /// <list type="table"> | |||
|
29 | /// <item> | |||
|
30 | /// <term><c>.</c></term> | |||
|
31 | /// <description>Разделяет элементы пространства имен</description> | |||
|
32 | /// <item> | |||
|
33 | /// <item> | |||
|
34 | /// <term><c>+</c></term> | |||
|
35 | /// <description>Разделяет вложенные типы</description> | |||
|
36 | /// <item> | |||
|
37 | /// <item> | |||
|
38 | /// <term><c>[]</c>, <c>[,,,]</c></term> | |||
|
39 | /// <description>Указывает на то, что тип является массивом, также указывается его размерность</description> | |||
|
40 | /// <item> | |||
|
41 | /// <item> | |||
|
42 | /// <term><c>{}</c>, <c>{,,}</c>, <c>{Int32,String}</c></term> | |||
|
43 | /// <description>Указывает на то, что тип является общим, также | |||
|
44 | /// указывается количество параметров, либо конкретные типы для | |||
|
45 | /// специализации</description> | |||
|
46 | /// <item> | |||
|
47 | /// </list> | |||
|
48 | /// </para> | |||
|
49 | /// </remarks> | |||
|
50 | public abstract class TypeReference { | |||
|
51 | ||||
|
52 | /// <summary> | |||
|
53 | /// Имя типа без дополнительных элементов, указывающих на то, что он общий или массив. | |||
|
54 | /// </summary> | |||
|
55 | /// <remarks> | |||
|
56 | /// Для массивов это имя его элементов. | |||
|
57 | /// </remarks> | |||
|
58 | public abstract string Name { get; } | |||
|
59 | ||||
|
60 | /// <summary> | |||
|
61 | /// Пространство имен в котором нахожится тип. | |||
|
62 | /// </summary> | |||
|
63 | /// <remarks> | |||
|
64 | /// Для вложенных типов это пространтство имен типа самого верхнего уровня, | |||
|
65 | /// для массивов - пространство имен его элементов. | |||
|
66 | /// </remarks> | |||
|
67 | public abstract string Namespace { get; } | |||
|
68 | ||||
|
69 | /// <summary> | |||
|
70 | /// Количество параметров общего типа. | |||
|
71 | /// </summary> | |||
|
72 | /// <remarks> | |||
|
73 | /// <para> | |||
|
74 | /// Вложенные типы неявно получают параметры от типов в которых они объявлены, | |||
|
75 | /// данное свойство это не учитывает, возвращается только количество собственных | |||
|
76 | /// параметров. | |||
|
77 | /// </para> | |||
|
78 | /// <para> | |||
|
79 | /// Данное свойство используется для получения CRL имени типа. | |||
|
80 | /// </para> | |||
|
81 | /// </remarks> | |||
|
82 | public abstract int GenericParametersCount { get; } | |||
|
83 | ||||
|
84 | public virtual string ClrName { | |||
|
85 | get { | |||
|
86 | return GenericParametersCount != 0 ? $"{Name}`{GenericParametersCount}" : Name; | |||
|
87 | } | |||
|
88 | } | |||
|
89 | ||||
|
90 | /// <summary> | |||
|
91 | /// Создает ссылку на специализацию текущего типа. | |||
|
92 | /// </summary> | |||
|
93 | /// <param name="genericParameters">Ссылки на типы, которые будут использоваться для специализации текущего типа.</param> | |||
|
94 | /// <returns>Специализация данного типа.</returns> | |||
|
95 | public virtual SpecializedTypeReference MakeGenericType(TypeReference[] genericParameters) { | |||
|
96 | if (GenericParametersCount == 0) | |||
|
97 | throw new InvalidOperationException("Can't specialize a non-geneic type"); | |||
|
98 | ||||
|
99 | if (genericParameters == null || GenericParametersCount != genericParameters.Length) | |||
|
100 | throw new InvalidOperationException("Generic parameters count mismatch"); | |||
|
101 | ||||
|
102 | return new SpecializedTypeReference(this, genericParameters); | |||
|
103 | } | |||
|
104 | ||||
|
105 | /// <summary> | |||
|
106 | /// Создает ссылку на тип массива указанной размерности, элементами которого являются экземпаляры даннго типа. | |||
|
107 | /// </summary> | |||
|
108 | /// <param name="rank">Размерность, если размерность <c>1</c> создается вектор (<see cref="Type.MakeArrayType()"/>).</param> | |||
|
109 | /// <returns>Ссылка на тип массива</returns> | |||
|
110 | public ArrayTypeReference MakeArrayType(int rank) { | |||
|
111 | Safe.ArgumentInRange(rank > 0, nameof(rank)); | |||
|
112 | ||||
|
113 | return new ArrayTypeReference(this, rank); | |||
|
114 | } | |||
|
115 | ||||
|
116 | /// <summary> | |||
|
117 | /// Создает ссылку на вложенный тип. | |||
|
118 | /// </summary> | |||
|
119 | /// <param name="name">Имя типа</param> | |||
|
120 | /// <param name="genericParameters">Количество параметров, если это общий тип, иначе 0.</param> | |||
|
121 | /// <returns>Ссылка на вложенный тип.</returns> | |||
|
122 | public TypeReference Create(string name, int genericParameters) { | |||
|
123 | Safe.ArgumentNotEmpty(name, nameof(name)); | |||
|
124 | Safe.ArgumentInRange(genericParameters >= 0, nameof(genericParameters)); | |||
|
125 | ||||
|
126 | return new NestedTypeReference(this, name, genericParameters); | |||
|
127 | } | |||
|
128 | ||||
|
129 | /// <summary> | |||
|
130 | /// Возвращает строковое представление ссылки на тип. | |||
|
131 | /// </summary> | |||
|
132 | /// <returns></returns> | |||
|
133 | public override string ToString() { | |||
|
134 | var builder = new StringBuilder(); | |||
|
135 | WriteTypeName(builder); | |||
|
136 | WriteTypeParams(builder); | |||
|
137 | return builder.ToString(); | |||
|
138 | } | |||
|
139 | ||||
|
140 | internal virtual void WriteTypeName(StringBuilder builder) { | |||
|
141 | if (!string.IsNullOrEmpty(Namespace)) | |||
|
142 | builder | |||
|
143 | .Append(Namespace) | |||
|
144 | .Append('.'); | |||
|
145 | builder.Append(Name); | |||
|
146 | } | |||
|
147 | ||||
|
148 | internal virtual void WriteTypeParams(StringBuilder builder) { | |||
|
149 | if (GenericParametersCount > 0) | |||
|
150 | builder | |||
|
151 | .Append('{') | |||
|
152 | .Append(',', GenericParametersCount-1) | |||
|
153 | .Append('}'); | |||
|
154 | } | |||
|
155 | ||||
|
156 | internal abstract void Visit(TypeResolutionContext visitor); | |||
|
157 | ||||
|
158 | /// <summary> | |||
|
159 | /// Создает ссылку на тип. | |||
|
160 | /// </summary> | |||
|
161 | /// <param name="ns">Пространство имен, либо его фрагмент.</param> | |||
|
162 | /// <param name="name">Имя типа без указания на количество параметров, либо на то, что это массив.</param> | |||
|
163 | /// <param name="genericParameters">Количество параметров типа, если это общий тип, иначе 0.</param> | |||
|
164 | /// <returns>Ссылка на тип.</returns> | |||
|
165 | public static TypeReference Create(string ns, string name, int genericParameters) { | |||
|
166 | Safe.ArgumentNotEmpty(name, nameof(name)); | |||
|
167 | Safe.ArgumentInRange(genericParameters >= 0, nameof(genericParameters)); | |||
|
168 | return new RootTypeReference(ns, name, genericParameters); | |||
|
169 | } | |||
|
170 | ||||
|
171 | /// <summary> | |||
|
172 | /// Разирает строковую запись ссылки на тип. | |||
|
173 | /// </summary> | |||
|
174 | /// <param name="typeSpec">Строковая запись ссылки на тип, например <c>Dictionary{String,String}</c></param> | |||
|
175 | /// <returns>Ссылка на тип.</returns> | |||
|
176 | public static TypeReference Parse(string typeSpec) { | |||
|
177 | var parser = new TypeReferenceParser(typeSpec); | |||
|
178 | return parser.Parse(); | |||
|
179 | } | |||
|
180 | ||||
|
181 | } | |||
|
182 | } No newline at end of file |
@@ -0,0 +1,245 | |||||
|
1 | using System; | |||
|
2 | using System.Collections.Generic; | |||
|
3 | using System.Linq; | |||
|
4 | using System.Text.RegularExpressions; | |||
|
5 | ||||
|
6 | namespace Implab.ServiceHost.Unity { | |||
|
7 | internal class TypeReferenceParser { | |||
|
8 | enum TokenType { | |||
|
9 | None, | |||
|
10 | ||||
|
11 | Word, | |||
|
12 | ||||
|
13 | Dot, | |||
|
14 | ||||
|
15 | Comma, | |||
|
16 | ||||
|
17 | OpenList, | |||
|
18 | ||||
|
19 | CloseList, | |||
|
20 | ||||
|
21 | OpenArray, | |||
|
22 | ||||
|
23 | CloseArray, | |||
|
24 | ||||
|
25 | Plus, | |||
|
26 | ||||
|
27 | Eof | |||
|
28 | } | |||
|
29 | ||||
|
30 | readonly Regex _tokens = new Regex(@"\G(?:([\w]+)|\s*([\+\.{},\[\]])\s*)", RegexOptions.Compiled); | |||
|
31 | ||||
|
32 | TokenType m_token; | |||
|
33 | ||||
|
34 | string m_tokenValue; | |||
|
35 | ||||
|
36 | int m_pos; | |||
|
37 | ||||
|
38 | int m_tokenPos; | |||
|
39 | ||||
|
40 | readonly string m_text; | |||
|
41 | ||||
|
42 | TokenType Token { get { return m_token; } } | |||
|
43 | ||||
|
44 | string TokenValue { get { return m_tokenValue; } } | |||
|
45 | ||||
|
46 | int TokenPos { get { return m_tokenPos; } } | |||
|
47 | ||||
|
48 | public TypeReferenceParser(string text) { | |||
|
49 | Safe.ArgumentNotEmpty(text, nameof(text)); | |||
|
50 | m_text = text; | |||
|
51 | } | |||
|
52 | ||||
|
53 | bool ReadToken() { | |||
|
54 | if (m_pos >= m_text.Length) { | |||
|
55 | m_token = TokenType.Eof; | |||
|
56 | m_tokenValue = null; | |||
|
57 | return false; | |||
|
58 | } | |||
|
59 | ||||
|
60 | var m = _tokens.Match(m_text, m_pos); | |||
|
61 | ||||
|
62 | if (m.Success) { | |||
|
63 | m_tokenPos = m_pos; | |||
|
64 | m_pos += m.Length; | |||
|
65 | if (m.Groups[1].Success) { | |||
|
66 | m_token = TokenType.Word; | |||
|
67 | m_tokenValue = m.Groups[1].Value; | |||
|
68 | } else if (m.Groups[2].Success) { | |||
|
69 | m_tokenValue = null; | |||
|
70 | switch (m.Groups[2].Value) { | |||
|
71 | case "{": | |||
|
72 | m_token = TokenType.OpenList; | |||
|
73 | break; | |||
|
74 | case "}": | |||
|
75 | m_token = TokenType.CloseList; | |||
|
76 | break; | |||
|
77 | case ".": | |||
|
78 | m_token = TokenType.Dot; | |||
|
79 | break; | |||
|
80 | case ",": | |||
|
81 | m_token = TokenType.Comma; | |||
|
82 | break; | |||
|
83 | case "[": | |||
|
84 | m_token = TokenType.OpenArray; | |||
|
85 | break; | |||
|
86 | case "]": | |||
|
87 | m_token = TokenType.CloseArray; | |||
|
88 | break; | |||
|
89 | case "+": | |||
|
90 | m_token = TokenType.Plus; | |||
|
91 | break; | |||
|
92 | } | |||
|
93 | } | |||
|
94 | return true; | |||
|
95 | } | |||
|
96 | throw new FormatException($"Failed to parse '{m_text}' at pos {m_pos}"); | |||
|
97 | } | |||
|
98 | ||||
|
99 | public TypeReference Parse() { | |||
|
100 | var result = ReadTypeReference(); | |||
|
101 | if (Token != TokenType.Eof) | |||
|
102 | ThrowUnexpectedToken(); | |||
|
103 | return result; | |||
|
104 | } | |||
|
105 | ||||
|
106 | string[] ReadQTypeName() { | |||
|
107 | var parts = new List<string>(); | |||
|
108 | ||||
|
109 | string current = null; | |||
|
110 | bool stop = false; | |||
|
111 | while ((!stop) && ReadToken()) { | |||
|
112 | switch (Token) { | |||
|
113 | case TokenType.Word: | |||
|
114 | if (current != null) | |||
|
115 | ThrowUnexpectedToken(); | |||
|
116 | current = TokenValue; | |||
|
117 | break; | |||
|
118 | case TokenType.Dot: | |||
|
119 | if (current == null) | |||
|
120 | ThrowUnexpectedToken(); | |||
|
121 | parts.Add(current); | |||
|
122 | current = null; | |||
|
123 | break; | |||
|
124 | default: | |||
|
125 | stop = true; | |||
|
126 | break; | |||
|
127 | } | |||
|
128 | } | |||
|
129 | if (current != null) | |||
|
130 | parts.Add(current); | |||
|
131 | ||||
|
132 | if (parts.Count == 0) | |||
|
133 | return null; | |||
|
134 | ||||
|
135 | return parts.ToArray(); | |||
|
136 | } | |||
|
137 | ||||
|
138 | string ReadNQTypeName() { | |||
|
139 | ReadToken(); | |||
|
140 | if (Token != TokenType.Word) | |||
|
141 | ThrowUnexpectedToken(); | |||
|
142 | return TokenValue; | |||
|
143 | } | |||
|
144 | ||||
|
145 | TypeReference ReadTypeReference() { | |||
|
146 | ||||
|
147 | var parts = ReadQTypeName(); | |||
|
148 | if (parts == null) | |||
|
149 | return null; | |||
|
150 | ||||
|
151 | var genericParameters = ReadGenericParams(); | |||
|
152 | ||||
|
153 | var typeReference = TypeReference.Create( | |||
|
154 | string.Join(".", parts, 0, parts.Length - 1), | |||
|
155 | parts[parts.Length - 1], | |||
|
156 | genericParameters.Length | |||
|
157 | ); | |||
|
158 | ||||
|
159 | if (genericParameters.Length > 0 && genericParameters.All(x => x != null)) | |||
|
160 | typeReference = typeReference.MakeGenericType(genericParameters); | |||
|
161 | ||||
|
162 | typeReference = ReadArraySpec(typeReference); | |||
|
163 | ||||
|
164 | if(Token == TokenType.Plus) | |||
|
165 | return ReadNestedType(typeReference); | |||
|
166 | ||||
|
167 | return typeReference; | |||
|
168 | } | |||
|
169 | ||||
|
170 | TypeReference ReadNestedType(TypeReference declaringType) { | |||
|
171 | var name = ReadNQTypeName(); | |||
|
172 | if(string.IsNullOrEmpty(name)) | |||
|
173 | throw new FormatException("Nested type name can't be empty"); | |||
|
174 | ReadToken(); | |||
|
175 | ||||
|
176 | var genericParameters = ReadGenericParams(); | |||
|
177 | ||||
|
178 | var typeReference = declaringType.Create( | |||
|
179 | name, | |||
|
180 | genericParameters.Length | |||
|
181 | ); | |||
|
182 | ||||
|
183 | if (genericParameters.Length > 0 && genericParameters.All(x => x != null)) | |||
|
184 | typeReference = typeReference.MakeGenericType(genericParameters); | |||
|
185 | ||||
|
186 | typeReference = ReadArraySpec(typeReference); | |||
|
187 | ||||
|
188 | if(Token == TokenType.Plus) | |||
|
189 | return ReadNestedType(typeReference); | |||
|
190 | ||||
|
191 | return typeReference; | |||
|
192 | } | |||
|
193 | ||||
|
194 | TypeReference[] ReadGenericParams() { | |||
|
195 | if (Token == TokenType.OpenList) { | |||
|
196 | var genericParameters = ReadTypeReferenceList(); | |||
|
197 | if (Token != TokenType.CloseList) | |||
|
198 | ThrowUnexpectedToken(); | |||
|
199 | ReadToken(); | |||
|
200 | ||||
|
201 | return genericParameters; | |||
|
202 | } | |||
|
203 | ||||
|
204 | return Array.Empty<TypeReference>(); | |||
|
205 | } | |||
|
206 | ||||
|
207 | TypeReference ReadArraySpec(TypeReference typeReference) { | |||
|
208 | while (Token == TokenType.OpenArray) { | |||
|
209 | var rank = CountRank(); | |||
|
210 | if (Token != TokenType.CloseArray) | |||
|
211 | ThrowUnexpectedToken(); | |||
|
212 | ||||
|
213 | typeReference = typeReference.MakeArrayType(rank); | |||
|
214 | ||||
|
215 | ReadToken(); | |||
|
216 | } | |||
|
217 | ||||
|
218 | return typeReference; | |||
|
219 | } | |||
|
220 | ||||
|
221 | int CountRank() { | |||
|
222 | int rank = 0; | |||
|
223 | do { | |||
|
224 | rank++; | |||
|
225 | } while(ReadToken() && Token == TokenType.Comma); | |||
|
226 | return rank; | |||
|
227 | } | |||
|
228 | ||||
|
229 | TypeReference[] ReadTypeReferenceList() { | |||
|
230 | var list = new List<TypeReference>(); | |||
|
231 | ||||
|
232 | do { | |||
|
233 | var typeReference = ReadTypeReference(); | |||
|
234 | list.Add(typeReference); | |||
|
235 | } while (Token == TokenType.Comma); | |||
|
236 | ||||
|
237 | return list.ToArray(); | |||
|
238 | } | |||
|
239 | ||||
|
240 | void ThrowUnexpectedToken() { | |||
|
241 | throw new FormatException($"Unexpected '{Token}' at pos {TokenPos}: -->{m_text.Substring(TokenPos, Math.Min(m_text.Length - TokenPos, 10))}"); | |||
|
242 | } | |||
|
243 | ||||
|
244 | } | |||
|
245 | } No newline at end of file |
@@ -0,0 +1,81 | |||||
|
1 | using System; | |||
|
2 | using System.Collections.Generic; | |||
|
3 | using System.Linq; | |||
|
4 | using Unity.Injection; | |||
|
5 | using Unity.Registration; | |||
|
6 | ||||
|
7 | namespace Implab.ServiceHost.Unity { | |||
|
8 | public class TypeRegistrationBuilder : RegistrationBuilder { | |||
|
9 | ||||
|
10 | readonly TypeResolver m_resolver; | |||
|
11 | ||||
|
12 | readonly List<InjectionMember> m_injections = new List<InjectionMember>(); | |||
|
13 | ||||
|
14 | internal InjectionMember[] Injections { get { return m_injections.ToArray(); } } | |||
|
15 | ||||
|
16 | public Type ImplementationType { | |||
|
17 | get; | |||
|
18 | private set; | |||
|
19 | } | |||
|
20 | ||||
|
21 | internal TypeRegistrationBuilder(TypeResolver resolver, Type registrationType, Type implementationType, ContainerBuilder root) : base(registrationType, root) { | |||
|
22 | ImplementationType = implementationType; | |||
|
23 | ||||
|
24 | // when registering a generic mapping, register all generic parameter names as local types | |||
|
25 | if (ImplementationType.IsGenericTypeDefinition) { | |||
|
26 | m_resolver = new TypeResolver(resolver); | |||
|
27 | ||||
|
28 | foreach (var p in ImplementationType.GetGenericArguments()) | |||
|
29 | m_resolver.AddMapping(p.Name, p); | |||
|
30 | } else { | |||
|
31 | m_resolver = resolver; | |||
|
32 | } | |||
|
33 | } | |||
|
34 | ||||
|
35 | internal void Visit(ConstructorInjectionElement constructorInjection) { | |||
|
36 | ||||
|
37 | ||||
|
38 | var parameters = constructorInjection.Parameters? | |||
|
39 | .Select(x => { | |||
|
40 | var valueBuilder = new InjectionParameterBuilder(m_resolver, null, Root); | |||
|
41 | x.Visit(valueBuilder); | |||
|
42 | return valueBuilder.Injection; | |||
|
43 | }) | |||
|
44 | .ToArray(); | |||
|
45 | ||||
|
46 | var injection = parameters != null ? new InjectionConstructor(parameters) : new InjectionConstructor(); | |||
|
47 | m_injections.Add(injection); | |||
|
48 | } | |||
|
49 | ||||
|
50 | internal void Visit(MethodInjectionElement methodInjection) { | |||
|
51 | var parameters = methodInjection.Parameters? | |||
|
52 | .Select(x => { | |||
|
53 | var valueBuilder = new InjectionParameterBuilder(m_resolver, null, Root); | |||
|
54 | x.Visit(valueBuilder); | |||
|
55 | return valueBuilder.Injection; | |||
|
56 | }) | |||
|
57 | .ToArray(); | |||
|
58 | ||||
|
59 | var injection = parameters != null ? new InjectionMethod(methodInjection.Name, parameters) : new InjectionMethod(methodInjection.Name); | |||
|
60 | m_injections.Add(injection); | |||
|
61 | } | |||
|
62 | ||||
|
63 | internal void Visit(PropertyInjectionElement propertyInjection) { | |||
|
64 | if (propertyInjection.Value == null) | |||
|
65 | throw new Exception($"A value value must be specified for the property '{propertyInjection.Name}'"); | |||
|
66 | ||||
|
67 | var propertyType = ImplementationType.GetProperty(propertyInjection.Name)?.PropertyType; | |||
|
68 | var valueContext = new InjectionParameterBuilder(m_resolver, propertyType, Root); | |||
|
69 | ||||
|
70 | propertyInjection.Value.Visit(valueContext); | |||
|
71 | var injection = new InjectionProperty(propertyInjection.Name, valueContext.Injection); | |||
|
72 | m_injections.Add(injection); | |||
|
73 | } | |||
|
74 | ||||
|
75 | public void AddInjectionMember(InjectionMember injection) { | |||
|
76 | Safe.ArgumentNotNull(injection, nameof(injection)); | |||
|
77 | ||||
|
78 | m_injections.Add(injection); | |||
|
79 | } | |||
|
80 | } | |||
|
81 | } No newline at end of file |
@@ -0,0 +1,75 | |||||
|
1 | using System; | |||
|
2 | using System.Collections.Generic; | |||
|
3 | using Implab.Diagnostics; | |||
|
4 | ||||
|
5 | namespace Implab.ServiceHost.Unity { | |||
|
6 | using static Trace<TypeResolver>; | |||
|
7 | ||||
|
8 | /// <summary> | |||
|
9 | /// Позволяет обойти вложенные типы и собрать цеочку из типов и параметров генериков, которые они предлагают | |||
|
10 | /// </summary> | |||
|
11 | internal class TypeResolutionContext { | |||
|
12 | readonly TypeResolver m_resolver; | |||
|
13 | ||||
|
14 | ||||
|
15 | readonly List<Type> m_genericParameters = new List<Type>(); | |||
|
16 | ||||
|
17 | public IEnumerable<Type> GenericParameters { get { return m_genericParameters; } } | |||
|
18 | ||||
|
19 | public Type ResolvedType { get; private set; } | |||
|
20 | ||||
|
21 | ||||
|
22 | public int ArrayRank { get; private set; } | |||
|
23 | ||||
|
24 | ||||
|
25 | public bool ThrowOnFail { get; private set; } | |||
|
26 | ||||
|
27 | public TypeResolutionContext(TypeResolver resolver, bool throwOnFail) { | |||
|
28 | m_resolver = resolver; | |||
|
29 | ThrowOnFail = throwOnFail; | |||
|
30 | } | |||
|
31 | ||||
|
32 | public Type MakeType() { | |||
|
33 | return m_genericParameters.Count > 0 ? | |||
|
34 | ResolvedType?.MakeGenericType(m_genericParameters.ToArray()) : | |||
|
35 | ResolvedType; | |||
|
36 | } | |||
|
37 | ||||
|
38 | public void Visit(SpecializedTypeReference typeReference) { | |||
|
39 | typeReference.GenericType.Visit(this); | |||
|
40 | ||||
|
41 | if (ResolvedType != null) { | |||
|
42 | foreach (var genericParamRef in typeReference.GenericParameters) { | |||
|
43 | var context = new TypeResolutionContext(m_resolver, ThrowOnFail); | |||
|
44 | genericParamRef.Visit(context); | |||
|
45 | m_genericParameters.Add(context.MakeType()); | |||
|
46 | } | |||
|
47 | } | |||
|
48 | } | |||
|
49 | ||||
|
50 | public void Visit(NestedTypeReference typeReference) { | |||
|
51 | typeReference.DeclaringType.Visit(this); | |||
|
52 | if (ResolvedType != null) | |||
|
53 | ResolvedType = ResolvedType?.GetNestedType(typeReference.ClrName) ?? Failed(typeReference); | |||
|
54 | } | |||
|
55 | ||||
|
56 | public void Visit(RootTypeReference typeReference) { | |||
|
57 | ResolvedType = m_resolver.Resolve(typeReference.Namespace, typeReference.ClrName) ?? Failed(typeReference); | |||
|
58 | } | |||
|
59 | ||||
|
60 | public void Visit(ArrayTypeReference typeReference) { | |||
|
61 | var context = new TypeResolutionContext(m_resolver, ThrowOnFail); | |||
|
62 | typeReference.ItemsType.Visit(context); | |||
|
63 | ResolvedType = typeReference.Rank == 1 ? | |||
|
64 | context.MakeType()?.MakeArrayType() : | |||
|
65 | context.MakeType()?.MakeArrayType(typeReference.Rank); | |||
|
66 | } | |||
|
67 | ||||
|
68 | Type Failed(TypeReference reference) { | |||
|
69 | Log($"Falied to resolve {reference}"); | |||
|
70 | if (ThrowOnFail) | |||
|
71 | throw new Exception($"Failed to resolve {reference}"); | |||
|
72 | return null; | |||
|
73 | } | |||
|
74 | } | |||
|
75 | } No newline at end of file |
@@ -0,0 +1,99 | |||||
|
1 | using System; | |||
|
2 | using System.Collections.Generic; | |||
|
3 | using System.Linq; | |||
|
4 | using System.Text; | |||
|
5 | using System.Text.RegularExpressions; | |||
|
6 | using Implab.Diagnostics; | |||
|
7 | ||||
|
8 | namespace Implab.ServiceHost.Unity { | |||
|
9 | using System.Diagnostics; | |||
|
10 | using static Trace<TypeResolver>; | |||
|
11 | public class TypeResolver { | |||
|
12 | readonly Dictionary<string, Type> m_cache = new Dictionary<string, Type>(); | |||
|
13 | ||||
|
14 | Regex _nsRx = new Regex(@"^\w+(\.\w+)*$", RegexOptions.Compiled); | |||
|
15 | readonly LinkedList<string> m_namespases = new LinkedList<string>(); | |||
|
16 | ||||
|
17 | internal Type Resolve(string ns, string typeName) { | |||
|
18 | var fullName = string.IsNullOrEmpty(ns) ? typeName : $"{ns}.{typeName}"; | |||
|
19 | ||||
|
20 | return ProbeInNamespaces(fullName); | |||
|
21 | } | |||
|
22 | ||||
|
23 | public Type Resolve(TypeReference typeReference, bool throwOnFail) { | |||
|
24 | var context = new TypeResolutionContext(this, throwOnFail); | |||
|
25 | typeReference.Visit(context); | |||
|
26 | return context.MakeType(); | |||
|
27 | } | |||
|
28 | ||||
|
29 | public Type Resolve(string typeSpec, bool throwOnFail) { | |||
|
30 | Safe.ArgumentNotEmpty(typeSpec, nameof(typeSpec)); | |||
|
31 | var typeReference = TypeReference.Parse(typeSpec); | |||
|
32 | return Resolve(typeReference, throwOnFail); | |||
|
33 | } | |||
|
34 | ||||
|
35 | LinkedListNode<string> m_insertAt; | |||
|
36 | ||||
|
37 | readonly TypeResolver m_parent; | |||
|
38 | ||||
|
39 | public TypeResolver() : this(null) { | |||
|
40 | } | |||
|
41 | ||||
|
42 | public TypeResolver(TypeResolver parent) { | |||
|
43 | m_parent = parent; | |||
|
44 | m_insertAt = new LinkedListNode<string>(string.Empty); | |||
|
45 | m_namespases.AddFirst(m_insertAt); | |||
|
46 | } | |||
|
47 | ||||
|
48 | public void AddNamespace(string ns) { | |||
|
49 | Safe.ArgumentMatch(ns, nameof(ns), _nsRx); | |||
|
50 | if (m_insertAt != null) | |||
|
51 | m_namespases.AddAfter(m_insertAt, ns); | |||
|
52 | else | |||
|
53 | m_namespases.AddFirst(ns); | |||
|
54 | } | |||
|
55 | ||||
|
56 | public void AddMapping(string typeName, Type type) { | |||
|
57 | Safe.ArgumentNotEmpty(typeName, nameof(typeName)); | |||
|
58 | Safe.ArgumentNotNull(type, nameof(type)); | |||
|
59 | ||||
|
60 | m_cache[typeName] = type; | |||
|
61 | } | |||
|
62 | ||||
|
63 | Type ProbeInNamespaces(string localName) { | |||
|
64 | ||||
|
65 | Type resolved; | |||
|
66 | if (!m_cache.TryGetValue(localName, out resolved)) { | |||
|
67 | foreach (var ns in m_namespases) { | |||
|
68 | var typeName = string.IsNullOrEmpty(ns) ? localName : $"{ns}.{localName}"; | |||
|
69 | resolved = Probe(typeName); | |||
|
70 | if (resolved != null) { | |||
|
71 | Log($"Probe '{localName}' -> '{resolved.FullName}'"); | |||
|
72 | break; | |||
|
73 | } | |||
|
74 | } | |||
|
75 | ||||
|
76 | if (resolved == null && m_parent != null) | |||
|
77 | resolved = m_parent.ProbeInNamespaces(localName); | |||
|
78 | ||||
|
79 | if(resolved == null) | |||
|
80 | Log($"Probe '{localName}' failed"); | |||
|
81 | ||||
|
82 | m_cache[localName] = resolved; | |||
|
83 | } | |||
|
84 | ||||
|
85 | return resolved; | |||
|
86 | } | |||
|
87 | ||||
|
88 | Type Probe(string typeName) { | |||
|
89 | var assemblies = AppDomain.CurrentDomain.GetAssemblies(); | |||
|
90 | ||||
|
91 | foreach (var assembly in assemblies) { | |||
|
92 | var type = assembly.GetType(typeName); | |||
|
93 | if (type != null) | |||
|
94 | return type; | |||
|
95 | } | |||
|
96 | return null; | |||
|
97 | } | |||
|
98 | } | |||
|
99 | } No newline at end of file |
@@ -0,0 +1,40 | |||||
|
1 | using System.IO; | |||
|
2 | using Unity; | |||
|
3 | ||||
|
4 | namespace Implab.ServiceHost.Unity | |||
|
5 | { | |||
|
6 | public static class UnityContainerExtensions | |||
|
7 | { | |||
|
8 | public static IUnityContainer LoadXmlConfiguration(this IUnityContainer container, string file, ContainerConfigurationSchema schema) { | |||
|
9 | Safe.ArgumentNotNull(container, nameof(container)); | |||
|
10 | var builder = new ContainerBuilder(container,schema); | |||
|
11 | builder.LoadConfig(file); | |||
|
12 | return builder.Container; | |||
|
13 | } | |||
|
14 | ||||
|
15 | public static IUnityContainer LoadXmlConfiguration(this IUnityContainer container, Stream stream, ContainerConfigurationSchema schema) { | |||
|
16 | Safe.ArgumentNotNull(container, nameof(container)); | |||
|
17 | Safe.ArgumentNotNull(stream, nameof(stream)); | |||
|
18 | ||||
|
19 | if (schema == null) | |||
|
20 | schema = ContainerConfigurationSchema.Default; | |||
|
21 | ||||
|
22 | var builder = new ContainerBuilder(container,schema); | |||
|
23 | var config = (ContainerElement)schema.Serializer.Deserialize(stream); | |||
|
24 | if (config.Items != null) { | |||
|
25 | foreach(var item in config.Items) | |||
|
26 | item?.Visit(builder); | |||
|
27 | } | |||
|
28 | ||||
|
29 | return builder.Container; | |||
|
30 | } | |||
|
31 | ||||
|
32 | public static IUnityContainer LoadXmlConfiguration(this IUnityContainer container, Stream stream) { | |||
|
33 | return LoadXmlConfiguration(container, stream, ContainerConfigurationSchema.Default); | |||
|
34 | } | |||
|
35 | ||||
|
36 | public static IUnityContainer LoadXmlConfiguration(this IUnityContainer container, string file) { | |||
|
37 | return LoadXmlConfiguration(container, file, ContainerConfigurationSchema.Default); | |||
|
38 | } | |||
|
39 | } | |||
|
40 | } No newline at end of file |
@@ -0,0 +1,36 | |||||
|
1 | using System.Collections.Generic; | |||
|
2 | using System.Xml.Serialization; | |||
|
3 | ||||
|
4 | namespace Implab.ServiceHost.Unity { | |||
|
5 | public class ValueElement : AbstractRegistration, IInstanceRegistration { | |||
|
6 | ||||
|
7 | [XmlAttribute("value")] | |||
|
8 | public string Value { get; set; } | |||
|
9 | ||||
|
10 | [XmlText] | |||
|
11 | public string Text { get; set; } | |||
|
12 | ||||
|
13 | string GetTextValue() { | |||
|
14 | return string.IsNullOrEmpty(Value) ? Text : Value; | |||
|
15 | } | |||
|
16 | ||||
|
17 | public string TypeName { | |||
|
18 | get { | |||
|
19 | return RegistrationType; | |||
|
20 | } | |||
|
21 | } | |||
|
22 | ||||
|
23 | public IEnumerable<IInjectionParameter> MemberInjections { | |||
|
24 | get { | |||
|
25 | yield return new ValueParameterElement { | |||
|
26 | Value = Value, | |||
|
27 | Text = Text | |||
|
28 | }; | |||
|
29 | } | |||
|
30 | } | |||
|
31 | ||||
|
32 | public override void Visit(ContainerBuilder builder) { | |||
|
33 | builder.Visit(this); | |||
|
34 | } | |||
|
35 | } | |||
|
36 | } No newline at end of file |
@@ -0,0 +1,21 | |||||
|
1 | using System.ComponentModel; | |||
|
2 | using System.Xml.Serialization; | |||
|
3 | ||||
|
4 | namespace Implab.ServiceHost.Unity { | |||
|
5 | public class ValueParameterElement : AbstractInjectionParameter { | |||
|
6 | [XmlAttribute("value")] | |||
|
7 | public string Value { get; set; } | |||
|
8 | ||||
|
9 | [XmlText] | |||
|
10 | public string Text { get; set; } | |||
|
11 | ||||
|
12 | string GetTextValue() { | |||
|
13 | return string.IsNullOrEmpty(Value) ? Text : Value; | |||
|
14 | } | |||
|
15 | ||||
|
16 | public override void Visit(InjectionParameterBuilder builder) { | |||
|
17 | var type = builder.ResolveInjectedValueType(TypeName); | |||
|
18 | builder.SetValue(type, TypeDescriptor.GetConverter(type).ConvertFromString(GetTextValue())); | |||
|
19 | } | |||
|
20 | } | |||
|
21 | } No newline at end of file |
@@ -0,0 +1,34 | |||||
|
1 | using System; | |||
|
2 | using System.Threading; | |||
|
3 | using System.Threading.Tasks; | |||
|
4 | using Implab.Components; | |||
|
5 | using Implab.Diagnostics; | |||
|
6 | using Xunit; | |||
|
7 | ||||
|
8 | namespace Implab.Test { | |||
|
9 | ||||
|
10 | public class DiagnosticsTest { | |||
|
11 | class Foo {} | |||
|
12 | ||||
|
13 | [Fact] | |||
|
14 | public void TestRegistration() { | |||
|
15 | var channel = TraceSourceChannel<Foo>.Default; | |||
|
16 | ||||
|
17 | Assert.Equal(typeof(Foo), channel.Id); | |||
|
18 | Assert.Equal(typeof(Foo).FullName, channel.Source.Name); | |||
|
19 | ||||
|
20 | TraceSourceChannel found = null; | |||
|
21 | int visited = 0; | |||
|
22 | ||||
|
23 | TraceRegistry.Global.Subscribe(x => { | |||
|
24 | visited++; | |||
|
25 | found = x as TraceSourceChannel; | |||
|
26 | }); | |||
|
27 | ||||
|
28 | Assert.Equal(1,visited); | |||
|
29 | Assert.Equal(channel, found); | |||
|
30 | ||||
|
31 | } | |||
|
32 | ||||
|
33 | } | |||
|
34 | } No newline at end of file |
@@ -0,0 +1,37 | |||||
|
1 | using System; | |||
|
2 | using System.Threading; | |||
|
3 | using System.Threading.Tasks; | |||
|
4 | using Implab.Components; | |||
|
5 | ||||
|
6 | namespace Implab.Test { | |||
|
7 | public class MockPollComponent : PollingComponent { | |||
|
8 | ||||
|
9 | public Func<CancellationToken,Task> PollWorker { get; set;} | |||
|
10 | ||||
|
11 | public Func<CancellationToken, Task> StartWorker { get; set; } | |||
|
12 | ||||
|
13 | public Func<CancellationToken, Task> StopWorker { get; set; } | |||
|
14 | ||||
|
15 | public MockPollComponent(bool initialized) : base(initialized) { | |||
|
16 | } | |||
|
17 | ||||
|
18 | protected async override Task Poll(CancellationToken ct) { | |||
|
19 | if(PollWorker!= null) | |||
|
20 | await PollWorker.Invoke(ct); | |||
|
21 | } | |||
|
22 | ||||
|
23 | protected async override Task StopInternalAsync(CancellationToken ct) { | |||
|
24 | await base.StopInternalAsync(ct); | |||
|
25 | if (StopWorker != null) | |||
|
26 | await StopWorker.Invoke(ct); | |||
|
27 | } | |||
|
28 | ||||
|
29 | protected async override Task StartInternalAsync(CancellationToken ct) { | |||
|
30 | await base.StartInternalAsync(ct); | |||
|
31 | if (StartWorker != null) | |||
|
32 | await StartWorker.Invoke(ct); | |||
|
33 | } | |||
|
34 | ||||
|
35 | ||||
|
36 | } | |||
|
37 | } No newline at end of file |
@@ -0,0 +1,20 | |||||
|
1 | using System.Xml.Serialization; | |||
|
2 | ||||
|
3 | namespace Implab.Test.Model { | |||
|
4 | ||||
|
5 | [XmlRoot(Namespace="urn:implab:test:model")] | |||
|
6 | public class Person { | |||
|
7 | public string FirstName { get; set; } | |||
|
8 | ||||
|
9 | public string LastName { get; set; } | |||
|
10 | ||||
|
11 | public int Age { get; set; } | |||
|
12 | ||||
|
13 | [XmlIgnore] | |||
|
14 | public bool AgeSpecified { get; set; } | |||
|
15 | ||||
|
16 | ||||
|
17 | [XmlElement("Tag")] | |||
|
18 | public string[] Tags { get; set; } | |||
|
19 | } | |||
|
20 | } No newline at end of file |
@@ -0,0 +1,264 | |||||
|
1 | using System; | |||
|
2 | using System.Threading; | |||
|
3 | using System.Threading.Tasks; | |||
|
4 | using Implab.Components; | |||
|
5 | using Xunit; | |||
|
6 | ||||
|
7 | namespace Implab.Test { | |||
|
8 | ||||
|
9 | public class RunnableComponentTests { | |||
|
10 | [Fact] | |||
|
11 | public async Task SimpleStartStop() { | |||
|
12 | ||||
|
13 | using (var m = new MockPollComponent(true)) { | |||
|
14 | m.StartWorker = async (ct) => await Task.Yield(); | |||
|
15 | m.StopWorker = async (ct) => await Task.Yield(); | |||
|
16 | ||||
|
17 | Assert.Equal(ExecutionState.Ready, m.State); | |||
|
18 | Assert.NotNull(m.Completion); | |||
|
19 | ||||
|
20 | m.Start(); | |||
|
21 | await m.Completion; | |||
|
22 | Assert.Equal(ExecutionState.Running, m.State); | |||
|
23 | ||||
|
24 | m.Stop(); | |||
|
25 | await m.Completion; | |||
|
26 | Assert.Equal(ExecutionState.Stopped, m.State); | |||
|
27 | } | |||
|
28 | } | |||
|
29 | ||||
|
30 | [Fact] | |||
|
31 | public async Task SyncStart() { | |||
|
32 | using (var m = new MockPollComponent(true)) { | |||
|
33 | m.Start(); | |||
|
34 | Assert.Equal(ExecutionState.Running, m.State); | |||
|
35 | await m.Completion; | |||
|
36 | } | |||
|
37 | } | |||
|
38 | ||||
|
39 | [Fact] | |||
|
40 | public async Task AsyncStarting() { | |||
|
41 | using (var m = new MockPollComponent(true)) { | |||
|
42 | var signal = Safe.CreateTask(); | |||
|
43 | ||||
|
44 | m.StartWorker = async (ct) => await signal; | |||
|
45 | m.Start(); | |||
|
46 | ||||
|
47 | Assert.Equal(ExecutionState.Starting, m.State); | |||
|
48 | Assert.False(m.Completion.IsCompleted); | |||
|
49 | ||||
|
50 | signal.Start(); | |||
|
51 | ||||
|
52 | await m.Completion; | |||
|
53 | ||||
|
54 | Assert.Equal(ExecutionState.Running, m.State); | |||
|
55 | } | |||
|
56 | } | |||
|
57 | ||||
|
58 | [Fact] | |||
|
59 | public async Task FailWhileStarting() { | |||
|
60 | using (var m = new MockPollComponent(true)) { | |||
|
61 | const string failMessage = "Fail me"; | |||
|
62 | var signal = new Task(() => { | |||
|
63 | throw new Exception(failMessage); | |||
|
64 | }); | |||
|
65 | ||||
|
66 | m.StartWorker = async (ct) => await signal; | |||
|
67 | m.Start(); | |||
|
68 | ||||
|
69 | Assert.Equal(ExecutionState.Starting, m.State); | |||
|
70 | Assert.False(m.Completion.IsCompleted); | |||
|
71 | ||||
|
72 | signal.Start(); | |||
|
73 | try { | |||
|
74 | await m.Completion; | |||
|
75 | Assert.True(false); | |||
|
76 | } catch (Exception e) { | |||
|
77 | Assert.Equal(failMessage, e.Message); | |||
|
78 | } | |||
|
79 | ||||
|
80 | Assert.Equal(ExecutionState.Failed, m.State); | |||
|
81 | } | |||
|
82 | } | |||
|
83 | ||||
|
84 | [Fact] | |||
|
85 | public async Task SyncStop() { | |||
|
86 | using (var m = new MockPollComponent(true)) { | |||
|
87 | m.Start(); | |||
|
88 | Assert.Equal(ExecutionState.Running, m.State); | |||
|
89 | m.Stop(); | |||
|
90 | Assert.Equal(ExecutionState.Stopped, m.State); | |||
|
91 | await m.Completion; | |||
|
92 | } | |||
|
93 | } | |||
|
94 | ||||
|
95 | [Fact] | |||
|
96 | public async Task AsyncStopping() { | |||
|
97 | using (var m = new MockPollComponent(true)) { | |||
|
98 | var signal = Safe.CreateTask(); | |||
|
99 | ||||
|
100 | m.StopWorker = async (ct) => await signal; | |||
|
101 | ||||
|
102 | // Start | |||
|
103 | m.Start(); | |||
|
104 | Assert.Equal(ExecutionState.Running, m.State); | |||
|
105 | ||||
|
106 | // Stop | |||
|
107 | m.Stop(); | |||
|
108 | Assert.Equal(ExecutionState.Stopping, m.State); | |||
|
109 | Assert.False(m.Completion.IsCompleted); | |||
|
110 | signal.Start(); | |||
|
111 | ||||
|
112 | await m.Completion; | |||
|
113 | ||||
|
114 | Assert.Equal(ExecutionState.Stopped, m.State); | |||
|
115 | } | |||
|
116 | } | |||
|
117 | ||||
|
118 | [Fact] | |||
|
119 | public async Task FailWhileStopping() { | |||
|
120 | using (var m = new MockPollComponent(true)) { | |||
|
121 | const string failMessage = "Fail me"; | |||
|
122 | var signal = new Task(() => { | |||
|
123 | throw new Exception(failMessage); | |||
|
124 | }); | |||
|
125 | ||||
|
126 | m.StopWorker = async (ct) => await signal; | |||
|
127 | ||||
|
128 | // Start | |||
|
129 | m.Start(); | |||
|
130 | Assert.Equal(ExecutionState.Running, m.State); | |||
|
131 | ||||
|
132 | // Stop | |||
|
133 | m.Stop(); | |||
|
134 | Assert.Equal(ExecutionState.Stopping, m.State); | |||
|
135 | Assert.False(m.Completion.IsCompleted); | |||
|
136 | ||||
|
137 | signal.Start(); | |||
|
138 | try { | |||
|
139 | await m.Completion; | |||
|
140 | Assert.True(false); | |||
|
141 | } catch (Exception e) { | |||
|
142 | Assert.Equal(failMessage, e.Message); | |||
|
143 | } | |||
|
144 | ||||
|
145 | Assert.Equal(ExecutionState.Failed, m.State); | |||
|
146 | } | |||
|
147 | } | |||
|
148 | ||||
|
149 | [Fact] | |||
|
150 | public async Task ThrowOnInvalidTrasition() { | |||
|
151 | using (var m = new MockPollComponent(false)) { | |||
|
152 | var started = Safe.CreateTask(); | |||
|
153 | var stopped = Safe.CreateTask(); | |||
|
154 | ||||
|
155 | m.StartWorker = async (ct) => await started; | |||
|
156 | m.StopWorker = async (ct) => await stopped; | |||
|
157 | ||||
|
158 | Assert.Throws<InvalidOperationException>(() => m.Start()); | |||
|
159 | ||||
|
160 | // Initialize | |||
|
161 | m.Initialize(); | |||
|
162 | await m.Completion; | |||
|
163 | ||||
|
164 | // Start | |||
|
165 | m.Start(); | |||
|
166 | Assert.Equal(ExecutionState.Starting, m.State); | |||
|
167 | ||||
|
168 | // Check invalid transitions | |||
|
169 | Assert.Throws<InvalidOperationException>(() => m.Start()); | |||
|
170 | ||||
|
171 | // Component can be stopped before started | |||
|
172 | // m.Stop(CancellationToken.None); | |||
|
173 | ||||
|
174 | // Running | |||
|
175 | started.Start(); | |||
|
176 | await m.Completion; | |||
|
177 | Assert.Equal(ExecutionState.Running, m.State); | |||
|
178 | ||||
|
179 | ||||
|
180 | Assert.Throws<InvalidOperationException>(() => m.Start()); | |||
|
181 | ||||
|
182 | // Stop | |||
|
183 | m.Stop(); | |||
|
184 | ||||
|
185 | // Check invalid transitions | |||
|
186 | Assert.Throws<InvalidOperationException>(() => m.Start()); | |||
|
187 | Assert.Throws<InvalidOperationException>(() => m.Stop()); | |||
|
188 | ||||
|
189 | // Stopped | |||
|
190 | stopped.Start(); | |||
|
191 | await m.Completion; | |||
|
192 | Assert.Equal(ExecutionState.Stopped, m.State); | |||
|
193 | ||||
|
194 | // Check invalid transitions | |||
|
195 | Assert.Throws<InvalidOperationException>(() => m.Start()); | |||
|
196 | Assert.Throws<InvalidOperationException>(() => m.Stop()); | |||
|
197 | } | |||
|
198 | } | |||
|
199 | ||||
|
200 | [Fact] | |||
|
201 | public async Task CancelStart() { | |||
|
202 | using (var m = new MockPollComponent(true)) { | |||
|
203 | m.StartWorker = (ct) => Safe.CreateTask(ct); | |||
|
204 | ||||
|
205 | m.Start(); | |||
|
206 | var start = m.Completion; | |||
|
207 | ||||
|
208 | Assert.Equal(ExecutionState.Starting, m.State); | |||
|
209 | m.Stop(); | |||
|
210 | await m.Completion; | |||
|
211 | Assert.Equal(ExecutionState.Stopped, m.State); | |||
|
212 | Assert.True(start.IsCompleted); | |||
|
213 | Assert.True(start.IsCanceled); | |||
|
214 | } | |||
|
215 | } | |||
|
216 | ||||
|
217 | [Fact] | |||
|
218 | public async Task AwaitWorker() { | |||
|
219 | using (var m = new MockPollComponent(true)) { | |||
|
220 | var worker = Safe.CreateTask(); | |||
|
221 | ||||
|
222 | m.PollWorker = (ct) => worker; | |||
|
223 | ||||
|
224 | m.Start(CancellationToken.None); | |||
|
225 | await m.Completion; | |||
|
226 | ||||
|
227 | Assert.Equal(ExecutionState.Running, m.State); | |||
|
228 | ||||
|
229 | m.Stop(CancellationToken.None); | |||
|
230 | Assert.Equal(ExecutionState.Stopping, m.State); | |||
|
231 | worker.Start(); | |||
|
232 | await m.Completion; | |||
|
233 | Assert.Equal(ExecutionState.Stopped, m.State); | |||
|
234 | } | |||
|
235 | } | |||
|
236 | ||||
|
237 | [Fact] | |||
|
238 | public async Task CancelWorker() { | |||
|
239 | using (var m = new MockPollComponent(true)) { | |||
|
240 | var worker = Safe.CreateTask(); | |||
|
241 | ||||
|
242 | var started = Safe.CreateTask(); | |||
|
243 | ||||
|
244 | m.PollWorker = async (ct) => { | |||
|
245 | started.Start(); | |||
|
246 | await worker; | |||
|
247 | ct.ThrowIfCancellationRequested(); | |||
|
248 | }; | |||
|
249 | ||||
|
250 | m.Start(CancellationToken.None); | |||
|
251 | await m.Completion; | |||
|
252 | await started; // await for the poll worker to start | |||
|
253 | ||||
|
254 | Assert.Equal(ExecutionState.Running, m.State); | |||
|
255 | ||||
|
256 | m.Stop(CancellationToken.None); | |||
|
257 | Assert.Equal(ExecutionState.Stopping, m.State); | |||
|
258 | worker.Start(); | |||
|
259 | await m.Completion; | |||
|
260 | Assert.Equal(ExecutionState.Stopped, m.State); | |||
|
261 | } | |||
|
262 | } | |||
|
263 | } | |||
|
264 | } |
@@ -0,0 +1,17 | |||||
|
1 | <?xml version="1.0"?> | |||
|
2 | <package > | |||
|
3 | <metadata> | |||
|
4 | <id>Implab</id> | |||
|
5 | <version>$version$</version> | |||
|
6 | <title>$title$</title> | |||
|
7 | <authors>Implab team</authors> | |||
|
8 | <owners>Implab team</owners> | |||
|
9 | <projectUrl>https://implab.org/</projectUrl> | |||
|
10 | <!-- <iconUrl>http://ICON_URL_HERE_OR_DELETE_THIS_LINE</iconUrl> --> | |||
|
11 | <requireLicenseAcceptance>false</requireLicenseAcceptance> | |||
|
12 | <description>Common components for asynchronous applications, tracing, logging, json and xml traits.</description> | |||
|
13 | <releaseNotes>Added strong name.</releaseNotes> | |||
|
14 | <copyright>Copyright 2017</copyright> | |||
|
15 | <tags>async xml json</tags> | |||
|
16 | </metadata> | |||
|
17 | </package> No newline at end of file |
1 | NO CONTENT: new file 100644, binary diff hidden |
|
NO CONTENT: new file 100644, binary diff hidden |
@@ -0,0 +1,22 | |||||
|
1 | Copyright 2012-2018 Sergey Smirnov | |||
|
2 | ||||
|
3 | Redistribution and use in source and binary forms, with or without | |||
|
4 | modification, are permitted provided that the following conditions are met: | |||
|
5 | ||||
|
6 | 1. Redistributions of source code must retain the above copyright notice, this | |||
|
7 | list of conditions and the following disclaimer. | |||
|
8 | ||||
|
9 | 2. Redistributions in binary form must reproduce the above copyright notice, | |||
|
10 | this list of conditions and the following disclaimer in the documentation | |||
|
11 | and/or other materials provided with the distribution. | |||
|
12 | ||||
|
13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |||
|
14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |||
|
15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
|
16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | |||
|
17 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||
|
18 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |||
|
19 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |||
|
20 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||
|
21 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |||
|
22 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. No newline at end of file |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
@@ -1,20 +1,29 | |||||
1 | syntax: glob |
|
1 | syntax: glob | |
2 | Implab.Test/bin/ |
|
2 | Implab.Test/bin/ | |
3 | *.user |
|
3 | *.user | |
4 | Implab.Test/obj/ |
|
4 | Implab.Test/obj/ | |
5 | *.userprefs |
|
5 | *.userprefs | |
6 | Implab/bin/ |
|
6 | Implab/bin/ | |
7 | Implab/obj/ |
|
7 | Implab/obj/ | |
8 | TestResults/ |
|
8 | TestResults/ | |
9 | Implab.Fx/obj/ |
|
9 | Implab.Fx/obj/ | |
10 | Implab.Fx/bin/ |
|
10 | Implab.Fx/bin/ | |
11 | Implab.Fx.Test/bin/ |
|
11 | Implab.Fx.Test/bin/ | |
12 | Implab.Fx.Test/obj/ |
|
12 | Implab.Fx.Test/obj/ | |
13 | _ReSharper.Implab/ |
|
13 | _ReSharper.Implab/ | |
14 | Implab.Diagnostics.Interactive/bin/ |
|
14 | Implab.Diagnostics.Interactive/bin/ | |
15 | Implab.Diagnostics.Interactive/obj/ |
|
15 | Implab.Diagnostics.Interactive/obj/ | |
16 | MonoPlay/bin/ |
|
16 | MonoPlay/bin/ | |
17 | MonoPlay/obj/ |
|
17 | MonoPlay/obj/ | |
18 | Implab.Test/Implab.Format.Test/bin/ |
|
18 | Implab.Test/Implab.Format.Test/bin/ | |
19 | Implab.Test/Implab.Format.Test/obj/ |
|
19 | Implab.Test/Implab.Format.Test/obj/ | |
20 | *.suo |
|
20 | *.suo | |
|
21 | Implab.Format.Test/bin/ | |||
|
22 | Implab.Format.Test/obj/ | |||
|
23 | packages/ | |||
|
24 | Implab.Playground/obj/ | |||
|
25 | Implab.Playground/bin/ | |||
|
26 | Implab.ServiceHost/bin/ | |||
|
27 | Implab.ServiceHost/obj/ | |||
|
28 | Implab.ServiceHost.Test/bin/ | |||
|
29 | Implab.ServiceHost.Test/obj/ |
@@ -1,1 +1,6 | |||||
1 | f1da3afc3521e0e1631ac19e09690bc0a241841a release v2.1 |
|
1 | f1da3afc3521e0e1631ac19e09690bc0a241841a release v2.1 | |
|
2 | 34df34841225f14ec65f4a5f28585d32b55829ad v3.0.1-beta | |||
|
3 | 547a2fc0d93ea5f867c778d7eeaa5888cc24fb9e v3.0.6 | |||
|
4 | f1696cdc3d7a5a9e19569567722285926c5d61b0 v3.0.8 | |||
|
5 | 74e048cbaac8cdd5a0825b1fd8b47dd932a05ae8 v3.0.10 | |||
|
6 | 95896f882995c74202bded87392585d287b16e82 v3.0.14 |
@@ -1,84 +1,24 | |||||
1 | <?xml version="1.0" encoding="utf-8"?> |
|
1 | <Project Sdk="Microsoft.NET.Sdk"> | |
2 | <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
|
2 | <PropertyGroup Condition="'$(OSTYPE)'=='linux'"> | |
3 | <PropertyGroup> |
|
3 | <TargetFrameworks>netcoreapp2.0;net46</TargetFrameworks> | |
4 | <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> |
|
4 | <FrameworkPathOverride Condition="'$(TargetFramework)'=='net46'">/usr/lib/mono/4.5/</FrameworkPathOverride> | |
5 | <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> |
|
|||
6 | <ProductVersion>8.0.30703</ProductVersion> |
|
|||
7 | <SchemaVersion>2.0</SchemaVersion> |
|
|||
8 | <ProjectGuid>{63F92C0C-61BF-48C0-A377-8D67C3C661D0}</ProjectGuid> |
|
|||
9 | <OutputType>Library</OutputType> |
|
|||
10 | <AppDesignerFolder>Properties</AppDesignerFolder> |
|
|||
11 | <RootNamespace>Implab.Test</RootNamespace> |
|
|||
12 | <AssemblyName>Implab.Test</AssemblyName> |
|
|||
13 | <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> |
|
|||
14 | <FileAlignment>512</FileAlignment> |
|
|||
15 | <ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> |
|
|||
16 | <TargetFrameworkProfile /> |
|
|||
17 | </PropertyGroup> |
|
5 | </PropertyGroup> | |
18 | <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> |
|
6 | ||
19 | <DebugSymbols>true</DebugSymbols> |
|
7 | <PropertyGroup Condition="'$(OSTYPE)'=='windows'"> | |
20 | <DebugType>full</DebugType> |
|
8 | <TargetFrameworks>netcoreapp2.0;net46</TargetFrameworks> | |
21 | <Optimize>false</Optimize> |
|
|||
22 | <OutputPath>bin\Debug\</OutputPath> |
|
|||
23 | <DefineConstants>DEBUG;TRACE</DefineConstants> |
|
|||
24 | <ErrorReport>prompt</ErrorReport> |
|
|||
25 | <WarningLevel>4</WarningLevel> |
|
|||
26 | <Prefer32Bit>false</Prefer32Bit> |
|
|||
27 | </PropertyGroup> |
|
|||
28 | <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> |
|
|||
29 | <DebugType>pdbonly</DebugType> |
|
|||
30 | <Optimize>true</Optimize> |
|
|||
31 | <OutputPath>bin\Release\</OutputPath> |
|
|||
32 | <DefineConstants>TRACE</DefineConstants> |
|
|||
33 | <ErrorReport>prompt</ErrorReport> |
|
|||
34 | <WarningLevel>4</WarningLevel> |
|
|||
35 | <Prefer32Bit>false</Prefer32Bit> |
|
|||
36 | </PropertyGroup> |
|
9 | </PropertyGroup> | |
37 | <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug 4.5|AnyCPU' "> |
|
10 | ||
38 | <DebugSymbols>true</DebugSymbols> |
|
11 | <PropertyGroup> | |
39 | <DebugType>full</DebugType> |
|
12 | <IsPackable>false</IsPackable> | |
40 | <Optimize>false</Optimize> |
|
|||
41 | <OutputPath>bin\Debug\</OutputPath> |
|
|||
42 | <DefineConstants>DEBUG;TRACE</DefineConstants> |
|
|||
43 | <ErrorReport>prompt</ErrorReport> |
|
|||
44 | <WarningLevel>4</WarningLevel> |
|
|||
45 | <Prefer32Bit>false</Prefer32Bit> |
|
|||
46 | </PropertyGroup> |
|
13 | </PropertyGroup> | |
47 | <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release 4.5|AnyCPU' "> |
|
14 | ||
48 | <DebugType>pdbonly</DebugType> |
|
|||
49 | <Optimize>true</Optimize> |
|
|||
50 | <OutputPath>bin\Release\</OutputPath> |
|
|||
51 | <DefineConstants>TRACE</DefineConstants> |
|
|||
52 | <ErrorReport>prompt</ErrorReport> |
|
|||
53 | <WarningLevel>4</WarningLevel> |
|
|||
54 | <Prefer32Bit>false</Prefer32Bit> |
|
|||
55 | </PropertyGroup> |
|
|||
56 | <ItemGroup> |
|
15 | <ItemGroup> | |
57 | <Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" /> |
|
16 | <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.6.0-preview-20180109-01" /> | |
58 | <Reference Include="System" /> |
|
17 | <PackageReference Include="System.Reactive" Version="4.0.0" /> | |
59 |
<Reference Include=" |
|
18 | <PackageReference Include="xunit" Version="2.3.1" /> | |
60 | <RequiredTargetFramework>3.5</RequiredTargetFramework> |
|
19 | <PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" /> | |
61 | </Reference> |
|
20 | <ProjectReference Include="../Implab/Implab.csproj"/> | |
62 | </ItemGroup> |
|
21 | <DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" /> | |
63 | <ItemGroup> |
|
|||
64 | <Compile Include="AsyncTests.cs" /> |
|
|||
65 | <Compile Include="CancelationTests.cs" /> |
|
|||
66 | <Compile Include="PromiseHelper.cs" /> |
|
|||
67 | <Compile Include="Properties\AssemblyInfo.cs" /> |
|
|||
68 | <Compile Include="RunnableComponentTests.cs" /> |
|
|||
69 | </ItemGroup> |
|
22 | </ItemGroup> | |
70 | <ItemGroup> |
|
23 | ||
71 | <ProjectReference Include="..\Implab\Implab.csproj"> |
|
24 | </Project> | |
72 | <Project>{99B95D0D-9CF9-4F70-8ADF-F4D0AA5CB0D9}</Project> |
|
|||
73 | <Name>Implab</Name> |
|
|||
74 | </ProjectReference> |
|
|||
75 | </ItemGroup> |
|
|||
76 | <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> |
|
|||
77 | <!-- To modify your build process, add your task inside one of the targets below and uncomment it. |
|
|||
78 | Other similar extension points exist, see Microsoft.Common.targets. |
|
|||
79 | <Target Name="BeforeBuild"> |
|
|||
80 | </Target> |
|
|||
81 | <Target Name="AfterBuild"> |
|
|||
82 | </Target> |
|
|||
83 | --> |
|
|||
84 | </Project> No newline at end of file |
|
@@ -1,88 +1,191 | |||||
1 | using NUnit.Framework; |
|
1 | using Xunit; | |
2 | using System; |
|
2 | using System; | |
3 | using Implab.Formats.JSON; |
|
|||
4 | using Implab.Automaton; |
|
3 | using Implab.Automaton; | |
|
4 | using Implab.Xml; | |||
|
5 | using System.Xml; | |||
|
6 | using Implab.Formats; | |||
|
7 | using Implab.Formats.Json; | |||
|
8 | using System.IO; | |||
|
9 | using Implab.Test.Model; | |||
5 |
|
10 | |||
6 |
namespace Implab. |
|
11 | namespace Implab.Test { | |
7 | [TestFixture] |
|
|||
8 | public class JsonTests { |
|
12 | public class JsonTests { | |
9 | [Test] |
|
13 | ||
|
14 | [Fact] | |||
10 | public void TestScannerValidTokens() { |
|
15 | public void TestScannerValidTokens() { | |
11 |
using (var scanner = |
|
16 | using (var scanner = JsonStringScanner.Create(@"9123, -123, 0, 0.1, -0.2, -0.1e3, 1.3E-3, ""some \t\n\u0020 text"", literal []{}:")) { | |
12 |
|
17 | |||
13 | Tuple<JsonTokenType,object>[] expexted = { |
|
18 | Tuple<JsonTokenType, object>[] expexted = { | |
14 |
new Tuple<JsonTokenType,object>(JsonTokenType.Number, |
|
19 | new Tuple<JsonTokenType,object>(JsonTokenType.Number, "9123"), | |
15 |
new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, |
|
20 | new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null), | |
16 |
new Tuple<JsonTokenType,object>(JsonTokenType.Number, |
|
21 | new Tuple<JsonTokenType,object>(JsonTokenType.Number, "-123"), | |
17 |
new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, |
|
22 | new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null), | |
18 |
new Tuple<JsonTokenType,object>(JsonTokenType.Number, |
|
23 | new Tuple<JsonTokenType,object>(JsonTokenType.Number, "0"), | |
19 |
new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, |
|
24 | new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null), | |
20 |
new Tuple<JsonTokenType,object>(JsonTokenType.Number, |
|
25 | new Tuple<JsonTokenType,object>(JsonTokenType.Number, "0.1"), | |
21 |
new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, |
|
26 | new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null), | |
22 |
new Tuple<JsonTokenType,object>(JsonTokenType.Number, |
|
27 | new Tuple<JsonTokenType,object>(JsonTokenType.Number, "-0.2"), | |
23 |
new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, |
|
28 | new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null), | |
24 |
new Tuple<JsonTokenType,object>(JsonTokenType.Number, -0.1e3 |
|
29 | new Tuple<JsonTokenType,object>(JsonTokenType.Number, "-0.1e3"), | |
25 |
new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, |
|
30 | new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null), | |
26 |
new Tuple<JsonTokenType,object>(JsonTokenType.Number, 1.3E-3 |
|
31 | new Tuple<JsonTokenType,object>(JsonTokenType.Number, "1.3E-3"), | |
27 |
new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, |
|
32 | new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null), | |
28 | new Tuple<JsonTokenType,object>(JsonTokenType.String, "some \t\n text"), |
|
33 | new Tuple<JsonTokenType,object>(JsonTokenType.String, "some \t\n text"), | |
29 |
new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, |
|
34 | new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null), | |
30 | new Tuple<JsonTokenType,object>(JsonTokenType.Literal, "literal"), |
|
35 | new Tuple<JsonTokenType,object>(JsonTokenType.Literal, "literal"), | |
31 |
new Tuple<JsonTokenType,object>(JsonTokenType.BeginArray, |
|
36 | new Tuple<JsonTokenType,object>(JsonTokenType.BeginArray, null), | |
32 |
new Tuple<JsonTokenType,object>(JsonTokenType.EndArray, |
|
37 | new Tuple<JsonTokenType,object>(JsonTokenType.EndArray, null), | |
33 |
new Tuple<JsonTokenType,object>(JsonTokenType.BeginObject, |
|
38 | new Tuple<JsonTokenType,object>(JsonTokenType.BeginObject, null), | |
34 |
new Tuple<JsonTokenType,object>(JsonTokenType.EndObject, |
|
39 | new Tuple<JsonTokenType,object>(JsonTokenType.EndObject, null), | |
35 |
new Tuple<JsonTokenType,object>(JsonTokenType.NameSeparator, |
|
40 | new Tuple<JsonTokenType,object>(JsonTokenType.NameSeparator, null) | |
36 | }; |
|
41 | }; | |
37 |
|
42 | |||
38 |
|
|
43 | string value; | |
39 | JsonTokenType tokenType; |
|
44 | JsonTokenType tokenType; | |
40 | for (var i = 0; i < expexted.Length; i++) { |
|
45 | for (var i = 0; i < expexted.Length; i++) { | |
41 |
|
46 | |||
42 |
Assert. |
|
47 | Assert.True(scanner.ReadToken(out value, out tokenType)); | |
43 |
Assert. |
|
48 | Assert.Equal(expexted[i].Item1, tokenType); | |
44 |
Assert. |
|
49 | Assert.Equal(expexted[i].Item2, value); | |
45 | } |
|
50 | } | |
46 |
|
51 | |||
47 |
Assert. |
|
52 | Assert.False(scanner.ReadToken(out value, out tokenType)); | |
48 | } |
|
53 | } | |
49 | } |
|
54 | } | |
50 |
|
55 | |||
51 |
[ |
|
56 | [Fact] | |
52 | public void TestScannerBadTokens() { |
|
57 | public void TestScannerBadTokens() { | |
53 |
var bad = new |
|
58 | var bad = new[] { | |
54 | " 1", |
|
59 | " 1", | |
55 | " literal", |
|
60 | " literal", | |
56 | " \"", |
|
61 | " \"", | |
57 | "\"unclosed string", |
|
62 | "\"unclosed string", | |
58 | "1.bad", |
|
63 | "1.bad", | |
59 | "001", // should be read as three numbers |
|
64 | "001", // should be read as three numbers | |
60 | "--10", |
|
65 | "--10", | |
61 | "+10", |
|
66 | "+10", | |
62 | "1.0.0", |
|
67 | "1.0.0", | |
63 | "1e1.0", |
|
68 | "1e1.0", | |
64 | "l1teral0", |
|
69 | "l1teral0", | |
65 | ".123", |
|
70 | ".123", | |
66 | "-.123" |
|
71 | "-.123" | |
67 | }; |
|
72 | }; | |
68 |
|
73 | |||
69 | foreach (var json in bad) |
|
74 | foreach (var json in bad) { | |
70 |
using (var scanner = |
|
75 | using (var scanner = JsonStringScanner.Create(json)) { | |
71 | try { |
|
76 | try { | |
72 |
|
|
77 | string value; | |
73 | JsonTokenType token; |
|
78 | JsonTokenType token; | |
74 | scanner.ReadToken(out value, out token); |
|
79 | scanner.ReadToken(out value, out token); | |
75 | if (!Object.Equals(value,json)) { |
|
80 | if (!Object.Equals(value, json)) { | |
76 |
Console.WriteLine("'{0}' is read as {1}", json, value is String ? String.Format("'{0}'", value) : value |
|
81 | Console.WriteLine("'{0}' is read as {1}", json, value is String ? String.Format("'{0}'", value) : value); | |
77 | continue; |
|
82 | continue; | |
78 | } |
|
83 | } | |
79 |
Assert. |
|
84 | Assert.True(false, $"Token '{json}' shouldn't pass"); | |
80 | } catch (ParserException e) { |
|
85 | } catch (ParserException e) { | |
81 | Console.WriteLine(e.Message); |
|
86 | Console.WriteLine(e.Message); | |
82 | } |
|
87 | } | |
83 | } |
|
88 | } | |
|
89 | } | |||
|
90 | } | |||
84 |
|
91 | |||
|
92 | [Fact] | |||
|
93 | public void JsonXmlReaderSimpleTest() { | |||
|
94 | //var json = "\"some text\""; | |||
|
95 | //Console.WriteLine($"JSON: {json}"); | |||
|
96 | //Console.WriteLine("XML"); | |||
|
97 | /*using (var xmlReader = new JsonXmlReader(new JSONParser(json), new JsonXmlReaderOptions { NamespaceUri = "JsonXmlReaderSimpleTest", RootName = "string", NodesPrefix = "json" })) { | |||
|
98 | Assert.AreEqual(xmlReader.ReadState, System.Xml.ReadState.Initial); | |||
|
99 | ||||
|
100 | AssertRead(xmlReader, XmlNodeType.XmlDeclaration); | |||
|
101 | AssertRead(xmlReader, XmlNodeType.Element); | |||
|
102 | AssertRead(xmlReader, XmlNodeType.Text); | |||
|
103 | AssertRead(xmlReader, XmlNodeType.EndElement); | |||
|
104 | Assert.IsFalse(xmlReader.Read()); | |||
|
105 | }*/ | |||
|
106 | ||||
|
107 | DumpJsonParse("\"text value\""); | |||
|
108 | DumpJsonParse("null"); | |||
|
109 | DumpJsonParse("true"); | |||
|
110 | DumpJsonParse("{}"); | |||
|
111 | DumpJsonParse("[]"); | |||
|
112 | DumpJsonParse("{\"one\":1, \"two\":2}"); | |||
|
113 | DumpJsonParse("[1,\"\",2,3]"); | |||
|
114 | DumpJsonParse("[{\"info\": [7,8,9]}]"); | |||
|
115 | DumpJsonFlatParse("[1,2,\"\",[3,4],{\"info\": [5,6]},{\"num\": [7,8,null]}, null,[null]]"); | |||
|
116 | } | |||
|
117 | ||||
|
118 | [Fact] | |||
|
119 | public void XmlToJsonTransform() { | |||
|
120 | var person = new Person { | |||
|
121 | FirstName = "Charlie", | |||
|
122 | LastName = "Brown", | |||
|
123 | Age = 19, | |||
|
124 | AgeSpecified = true | |||
|
125 | }; | |||
|
126 | ||||
|
127 | var doc = SerializationHelpers.SerializeAsXmlDocument(person); | |||
|
128 | ||||
|
129 | using (var writer = new StringWriter()) { | |||
|
130 | XmlToJson.Default.Transform(doc,null, writer); | |||
|
131 | Console.WriteLine(writer.ToString()); | |||
|
132 | } | |||
|
133 | } | |||
|
134 | ||||
|
135 | [Fact] | |||
|
136 | public void JsonSerialization() { | |||
|
137 | var person = new Person { | |||
|
138 | FirstName = "Charlie", | |||
|
139 | LastName = "Brown", | |||
|
140 | Age = 19, | |||
|
141 | AgeSpecified = true, | |||
|
142 | Tags = new [] { "brave", "stupid" } | |||
|
143 | }; | |||
|
144 | ||||
|
145 | var data = SerializationHelpers.SerializeJsonAsString(person); | |||
|
146 | Console.WriteLine(data); | |||
|
147 | var clone = SerializationHelpers.DeserializeJsonFromString<Person>(data); | |||
|
148 | ||||
|
149 | Assert.Equal(person.FirstName, clone.FirstName); | |||
|
150 | Assert.Equal(person.LastName, clone.LastName); | |||
|
151 | Assert.Equal(person.Age, clone.Age); | |||
|
152 | Assert.Equal(person.AgeSpecified, clone.AgeSpecified); | |||
|
153 | Assert.Equal(person.Tags, person.Tags); | |||
|
154 | } | |||
|
155 | ||||
|
156 | void AssertRead(XmlReader reader, XmlNodeType expected) { | |||
|
157 | Assert.True(reader.Read()); | |||
|
158 | Console.WriteLine($"{new string(' ', reader.Depth * 2)}{reader}"); | |||
|
159 | Assert.Equal(expected, reader.NodeType); | |||
|
160 | } | |||
|
161 | ||||
|
162 | void DumpJsonParse(string json) { | |||
|
163 | Console.WriteLine($"JSON: {json}"); | |||
|
164 | Console.WriteLine("XML"); | |||
|
165 | using (var xmlWriter = XmlWriter.Create(Console.Out, new XmlWriterSettings { | |||
|
166 | Indent = true, | |||
|
167 | CloseOutput = false, | |||
|
168 | ConformanceLevel = ConformanceLevel.Document | |||
|
169 | })) | |||
|
170 | using (var xmlReader = new JsonXmlReader(JsonReader.ParseString(json), new JsonXmlReaderOptions { NamespaceUri = "JsonXmlReaderSimpleTest", RootName = "Data", NodesPrefix = "json", CaseTransform = JsonXmlCaseTransform.UcFirst, ArrayItemName = "Item" })) { | |||
|
171 | xmlWriter.WriteNode(xmlReader, false); | |||
|
172 | } | |||
|
173 | Console.WriteLine(); | |||
|
174 | } | |||
|
175 | ||||
|
176 | void DumpJsonFlatParse(string json) { | |||
|
177 | Console.WriteLine($"JSON: {json}"); | |||
|
178 | Console.WriteLine("XML"); | |||
|
179 | using (var xmlWriter = XmlWriter.Create(Console.Out, new XmlWriterSettings { | |||
|
180 | Indent = true, | |||
|
181 | CloseOutput = false, | |||
|
182 | ConformanceLevel = ConformanceLevel.Document | |||
|
183 | })) | |||
|
184 | using (var xmlReader = new JsonXmlReader(JsonReader.ParseString(json), new JsonXmlReaderOptions { NamespaceUri = "JsonXmlReaderSimpleTest", NodesPrefix = "", FlattenArrays = true })) { | |||
|
185 | xmlWriter.WriteNode(xmlReader, false); | |||
|
186 | } | |||
|
187 | Console.WriteLine(); | |||
85 | } |
|
188 | } | |
86 | } |
|
189 | } | |
87 | } |
|
190 | } | |
88 |
|
191 |
@@ -1,14 +1,40 | |||||
1 |
using Implab |
|
1 | using Implab; | |
|
2 | using System; | |||
2 | using System.Threading; |
|
3 | using System.Threading; | |
3 |
|
4 | |||
4 | namespace Implab.Test { |
|
5 | namespace Implab.Test { | |
5 | static class PromiseHelper { |
|
6 | static class PromiseHelper { | |
6 | public static IPromise<T> Sleep<T>(int timeout, T retVal) { |
|
7 | public static IPromise<T> Sleep<T>(int timeout, T retVal, CancellationToken ct = default(CancellationToken)) { | |
7 | return AsyncPool.Invoke((ct) => { |
|
8 | ||
8 | ct.CancellationRequested(ct.CancelOperation); |
|
9 | Timer timer = null; | |
9 | Thread.Sleep(timeout); |
|
10 | ||
10 | return retVal; |
|
11 | return Promise.Create<T>((d) => { | |
|
12 | timer = new Timer(x => { | |||
|
13 | d.Resolve(retVal); | |||
|
14 | }, null, timeout, Timeout.Infinite); | |||
|
15 | ||||
|
16 | if(ct.CanBeCanceled) | |||
|
17 | ct.Register(d.Cancel); | |||
|
18 | ||||
|
19 | }).Finally(() => { | |||
|
20 | Safe.Dispose(timer); | |||
|
21 | }); | |||
|
22 | } | |||
|
23 | ||||
|
24 | public static IPromise Sleep(int timeout, CancellationToken ct = default(CancellationToken)) { | |||
|
25 | Timer timer = null; | |||
|
26 | ||||
|
27 | return Promise.Create((d) => { | |||
|
28 | timer = new Timer(x => { | |||
|
29 | d.Resolve(); | |||
|
30 | }, null, timeout, Timeout.Infinite); | |||
|
31 | ||||
|
32 | if(ct.CanBeCanceled) | |||
|
33 | ct.Register(d.Cancel); | |||
|
34 | ||||
|
35 | }).Finally(() => { | |||
|
36 | Safe.Dispose(timer); | |||
11 | }); |
|
37 | }); | |
12 | } |
|
38 | } | |
13 | } |
|
39 | } | |
14 | } |
|
40 | } |
@@ -1,270 +1,69 | |||||
1 |
|
|
1 | ||
2 |
Microsoft Visual Studio Solution File, Format Version 1 |
|
2 | Microsoft Visual Studio Solution File, Format Version 12.00 | |
3 |
# Visual Studio |
|
3 | # Visual Studio 15 | |
4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Implab", "Implab\Implab.csproj", "{F550F1F8-8746-4AD0-9614-855F4C4B7F05}" |
|
4 | VisualStudioVersion = 15.0.27428.2005 | |
|
5 | MinimumVisualStudioVersion = 10.0.40219.1 | |||
|
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Implab", "Implab\Implab.csproj", "{FF2052B6-9C8F-4022-A347-F07ABF635885}" | |||
5 | EndProject |
|
7 | EndProject | |
6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{CE8D8D18-437A-445C-B662-4C2CE79A76F6}" |
|
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Implab.Test", "Implab.Test\Implab.Test.csproj", "{6CD0DA18-8D9B-4AA8-A3DC-17322E27335E}" | |
7 | ProjectSection(SolutionItems) = preProject |
|
9 | EndProject | |
8 | Implab.vsmdi = Implab.vsmdi |
|
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Implab.Playground", "Implab.Playground\Implab.Playground.csproj", "{100DFEB0-75BE-436F-ADDF-1F46EF433F46}" | |
9 | Local.testsettings = Local.testsettings |
|
|||
10 | TraceAndTestImpact.testsettings = TraceAndTestImpact.testsettings |
|
|||
11 | EndProjectSection |
|
|||
12 | EndProject |
|
11 | EndProject | |
13 |
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Implab. |
|
12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Implab.ServiceHost", "Implab.ServiceHost\Implab.ServiceHost.csproj", "{8B79FCBE-50DD-40A0-9B5E-E572072E4868}" | |
14 | EndProject |
|
13 | EndProject | |
15 |
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Implab. |
|
14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Implab.ServiceHost.Test", "Implab.ServiceHost.Test\Implab.ServiceHost.Test.csproj", "{CB844F94-E555-4F25-A932-7CB85C98CF86}" | |
16 | EndProject |
|
|||
17 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Implab.Fx.Test", "Implab.Fx.Test\Implab.Fx.Test.csproj", "{2F31E405-E267-4195-A05D-574093C21209}" |
|
|||
18 | EndProject |
|
15 | EndProject | |
19 | Global |
|
16 | Global | |
20 | GlobalSection(SolutionConfigurationPlatforms) = preSolution |
|
17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution | |
21 | Debug|Any CPU = Debug|Any CPU |
|
18 | Debug|Any CPU = Debug|Any CPU | |
22 | Release|Any CPU = Release|Any CPU |
|
19 | Release|Any CPU = Release|Any CPU | |
23 | Debug 4.5|Any CPU = Debug 4.5|Any CPU |
|
20 | Debug|x64 = Debug|x64 | |
24 | Release 4.5|Any CPU = Release 4.5|Any CPU |
|
21 | Debug|x86 = Debug|x86 | |
|
22 | Release|x64 = Release|x64 | |||
|
23 | Release|x86 = Release|x86 | |||
25 | EndGlobalSection |
|
24 | EndGlobalSection | |
26 | GlobalSection(ProjectConfigurationPlatforms) = postSolution |
|
25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution | |
27 |
{ |
|
26 | {FF2052B6-9C8F-4022-A347-F07ABF635885}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
28 |
{ |
|
27 | {FF2052B6-9C8F-4022-A347-F07ABF635885}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
29 | {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
|
28 | {FF2052B6-9C8F-4022-A347-F07ABF635885}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
30 | {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Debug|Any CPU.Build.0 = Debug|Any CPU |
|
29 | {FF2052B6-9C8F-4022-A347-F07ABF635885}.Release|Any CPU.Build.0 = Release|Any CPU | |
31 | {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Release 4.5|Any CPU.ActiveCfg = Release 4.5|Any CPU |
|
30 | {6CD0DA18-8D9B-4AA8-A3DC-17322E27335E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
32 | {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Release 4.5|Any CPU.Build.0 = Release 4.5|Any CPU |
|
31 | {6CD0DA18-8D9B-4AA8-A3DC-17322E27335E}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
33 |
{ |
|
32 | {6CD0DA18-8D9B-4AA8-A3DC-17322E27335E}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
34 |
{ |
|
33 | {6CD0DA18-8D9B-4AA8-A3DC-17322E27335E}.Release|Any CPU.Build.0 = Release|Any CPU | |
35 |
{ |
|
34 | {100DFEB0-75BE-436F-ADDF-1F46EF433F46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
36 |
{ |
|
35 | {100DFEB0-75BE-436F-ADDF-1F46EF433F46}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
37 |
{ |
|
36 | {100DFEB0-75BE-436F-ADDF-1F46EF433F46}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
38 | {2F31E405-E267-4195-A05D-574093C21209}.Debug|Any CPU.Build.0 = Debug|Any CPU |
|
37 | {100DFEB0-75BE-436F-ADDF-1F46EF433F46}.Release|Any CPU.Build.0 = Release|Any CPU | |
39 | {2F31E405-E267-4195-A05D-574093C21209}.Release 4.5|Any CPU.ActiveCfg = Release 4.5|Any CPU |
|
38 | {8B79FCBE-50DD-40A0-9B5E-E572072E4868}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
40 | {2F31E405-E267-4195-A05D-574093C21209}.Release 4.5|Any CPU.Build.0 = Release 4.5|Any CPU |
|
39 | {8B79FCBE-50DD-40A0-9B5E-E572072E4868}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
41 | {2F31E405-E267-4195-A05D-574093C21209}.Release|Any CPU.ActiveCfg = Release|Any CPU |
|
40 | {8B79FCBE-50DD-40A0-9B5E-E572072E4868}.Debug|x64.ActiveCfg = Debug|x64 | |
42 | {2F31E405-E267-4195-A05D-574093C21209}.Release|Any CPU.Build.0 = Release|Any CPU |
|
41 | {8B79FCBE-50DD-40A0-9B5E-E572072E4868}.Debug|x64.Build.0 = Debug|x64 | |
43 | {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Debug 4.5|Any CPU.ActiveCfg = Debug 4.5|Any CPU |
|
42 | {8B79FCBE-50DD-40A0-9B5E-E572072E4868}.Debug|x86.ActiveCfg = Debug|x86 | |
44 | {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Debug 4.5|Any CPU.Build.0 = Debug 4.5|Any CPU |
|
43 | {8B79FCBE-50DD-40A0-9B5E-E572072E4868}.Debug|x86.Build.0 = Debug|x86 | |
45 | {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
|
44 | {8B79FCBE-50DD-40A0-9B5E-E572072E4868}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
46 | {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Debug|Any CPU.Build.0 = Debug|Any CPU |
|
45 | {8B79FCBE-50DD-40A0-9B5E-E572072E4868}.Release|Any CPU.Build.0 = Release|Any CPU | |
47 | {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Release 4.5|Any CPU.ActiveCfg = Release 4.5|Any CPU |
|
46 | {8B79FCBE-50DD-40A0-9B5E-E572072E4868}.Release|x64.ActiveCfg = Release|x64 | |
48 | {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Release 4.5|Any CPU.Build.0 = Release 4.5|Any CPU |
|
47 | {8B79FCBE-50DD-40A0-9B5E-E572072E4868}.Release|x64.Build.0 = Release|x64 | |
49 | {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Release|Any CPU.ActiveCfg = Release|Any CPU |
|
48 | {8B79FCBE-50DD-40A0-9B5E-E572072E4868}.Release|x86.ActiveCfg = Release|x86 | |
50 | {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Release|Any CPU.Build.0 = Release|Any CPU |
|
49 | {8B79FCBE-50DD-40A0-9B5E-E572072E4868}.Release|x86.Build.0 = Release|x86 | |
51 |
{ |
|
50 | {CB844F94-E555-4F25-A932-7CB85C98CF86}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
52 |
{ |
|
51 | {CB844F94-E555-4F25-A932-7CB85C98CF86}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
53 | {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
|
52 | {CB844F94-E555-4F25-A932-7CB85C98CF86}.Debug|x64.ActiveCfg = Debug|x64 | |
54 | {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Debug|Any CPU.Build.0 = Debug|Any CPU |
|
53 | {CB844F94-E555-4F25-A932-7CB85C98CF86}.Debug|x64.Build.0 = Debug|x64 | |
55 | {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Release 4.5|Any CPU.ActiveCfg = Release 4.5|Any CPU |
|
54 | {CB844F94-E555-4F25-A932-7CB85C98CF86}.Debug|x86.ActiveCfg = Debug|x86 | |
56 | {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Release 4.5|Any CPU.Build.0 = Release 4.5|Any CPU |
|
55 | {CB844F94-E555-4F25-A932-7CB85C98CF86}.Debug|x86.Build.0 = Debug|x86 | |
57 |
{ |
|
56 | {CB844F94-E555-4F25-A932-7CB85C98CF86}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
58 |
{ |
|
57 | {CB844F94-E555-4F25-A932-7CB85C98CF86}.Release|Any CPU.Build.0 = Release|Any CPU | |
59 | EndGlobalSection |
|
58 | {CB844F94-E555-4F25-A932-7CB85C98CF86}.Release|x64.ActiveCfg = Release|x64 | |
60 | GlobalSection(NestedProjects) = preSolution |
|
59 | {CB844F94-E555-4F25-A932-7CB85C98CF86}.Release|x64.Build.0 = Release|x64 | |
61 | EndGlobalSection |
|
60 | {CB844F94-E555-4F25-A932-7CB85C98CF86}.Release|x86.ActiveCfg = Release|x86 | |
62 | GlobalSection(MonoDevelopProperties) = preSolution |
|
61 | {CB844F94-E555-4F25-A932-7CB85C98CF86}.Release|x86.Build.0 = Release|x86 | |
63 | StartupItem = Implab\Implab.csproj |
|
|||
64 | Policies = $0 |
|
|||
65 | $0.CSharpFormattingPolicy = $1 |
|
|||
66 | $1.IndentSwitchBody = True |
|
|||
67 | $1.NamespaceBraceStyle = EndOfLine |
|
|||
68 | $1.ClassBraceStyle = EndOfLine |
|
|||
69 | $1.InterfaceBraceStyle = EndOfLine |
|
|||
70 | $1.StructBraceStyle = EndOfLine |
|
|||
71 | $1.EnumBraceStyle = EndOfLine |
|
|||
72 | $1.MethodBraceStyle = EndOfLine |
|
|||
73 | $1.ConstructorBraceStyle = EndOfLine |
|
|||
74 | $1.DestructorBraceStyle = EndOfLine |
|
|||
75 | $1.BeforeMethodDeclarationParentheses = False |
|
|||
76 | $1.BeforeMethodCallParentheses = False |
|
|||
77 | $1.BeforeConstructorDeclarationParentheses = False |
|
|||
78 | $1.NewLineBeforeConstructorInitializerColon = NewLine |
|
|||
79 | $1.NewLineAfterConstructorInitializerColon = SameLine |
|
|||
80 | $1.BeforeIndexerDeclarationBracket = False |
|
|||
81 | $1.BeforeDelegateDeclarationParentheses = False |
|
|||
82 | $1.NewParentheses = False |
|
|||
83 | $1.SpacesBeforeBrackets = False |
|
|||
84 | $1.inheritsSet = Mono |
|
|||
85 | $1.inheritsScope = text/x-csharp |
|
|||
86 | $1.scope = text/x-csharp |
|
|||
87 | $0.TextStylePolicy = $2 |
|
|||
88 | $2.FileWidth = 120 |
|
|||
89 | $2.EolMarker = Unix |
|
|||
90 | $2.inheritsSet = VisualStudio |
|
|||
91 | $2.inheritsScope = text/plain |
|
|||
92 | $2.scope = text/x-csharp |
|
|||
93 | $0.DotNetNamingPolicy = $3 |
|
|||
94 | $3.DirectoryNamespaceAssociation = PrefixedHierarchical |
|
|||
95 | $3.ResourceNamePolicy = MSBuild |
|
|||
96 | $0.TextStylePolicy = $4 |
|
|||
97 | $4.FileWidth = 120 |
|
|||
98 | $4.TabsToSpaces = False |
|
|||
99 | $4.inheritsSet = VisualStudio |
|
|||
100 | $4.inheritsScope = text/plain |
|
|||
101 | $4.scope = application/xml |
|
|||
102 | $0.XmlFormattingPolicy = $5 |
|
|||
103 | $5.inheritsSet = Mono |
|
|||
104 | $5.inheritsScope = application/xml |
|
|||
105 | $5.scope = application/xml |
|
|||
106 | $0.TextStylePolicy = $6 |
|
|||
107 | $6.FileWidth = 120 |
|
|||
108 | $6.TabsToSpaces = False |
|
|||
109 | $6.inheritsSet = VisualStudio |
|
|||
110 | $6.inheritsScope = text/plain |
|
|||
111 | $6.scope = text/plain |
|
|||
112 | $0.NameConventionPolicy = $7 |
|
|||
113 | $7.Rules = $8 |
|
|||
114 | $8.NamingRule = $9 |
|
|||
115 | $9.Name = Namespaces |
|
|||
116 | $9.AffectedEntity = Namespace |
|
|||
117 | $9.VisibilityMask = VisibilityMask |
|
|||
118 | $9.NamingStyle = PascalCase |
|
|||
119 | $9.IncludeInstanceMembers = True |
|
|||
120 | $9.IncludeStaticEntities = True |
|
|||
121 | $8.NamingRule = $10 |
|
|||
122 | $10.Name = Types |
|
|||
123 | $10.AffectedEntity = Class, Struct, Enum, Delegate |
|
|||
124 | $10.VisibilityMask = VisibilityMask |
|
|||
125 | $10.NamingStyle = PascalCase |
|
|||
126 | $10.IncludeInstanceMembers = True |
|
|||
127 | $10.IncludeStaticEntities = True |
|
|||
128 | $8.NamingRule = $11 |
|
|||
129 | $11.Name = Interfaces |
|
|||
130 | $11.RequiredPrefixes = $12 |
|
|||
131 | $12.String = I |
|
|||
132 | $11.AffectedEntity = Interface |
|
|||
133 | $11.VisibilityMask = VisibilityMask |
|
|||
134 | $11.NamingStyle = PascalCase |
|
|||
135 | $11.IncludeInstanceMembers = True |
|
|||
136 | $11.IncludeStaticEntities = True |
|
|||
137 | $8.NamingRule = $13 |
|
|||
138 | $13.Name = Attributes |
|
|||
139 | $13.RequiredSuffixes = $14 |
|
|||
140 | $14.String = Attribute |
|
|||
141 | $13.AffectedEntity = CustomAttributes |
|
|||
142 | $13.VisibilityMask = VisibilityMask |
|
|||
143 | $13.NamingStyle = PascalCase |
|
|||
144 | $13.IncludeInstanceMembers = True |
|
|||
145 | $13.IncludeStaticEntities = True |
|
|||
146 | $8.NamingRule = $15 |
|
|||
147 | $15.Name = Event Arguments |
|
|||
148 | $15.RequiredSuffixes = $16 |
|
|||
149 | $16.String = EventArgs |
|
|||
150 | $15.AffectedEntity = CustomEventArgs |
|
|||
151 | $15.VisibilityMask = VisibilityMask |
|
|||
152 | $15.NamingStyle = PascalCase |
|
|||
153 | $15.IncludeInstanceMembers = True |
|
|||
154 | $15.IncludeStaticEntities = True |
|
|||
155 | $8.NamingRule = $17 |
|
|||
156 | $17.Name = Exceptions |
|
|||
157 | $17.RequiredSuffixes = $18 |
|
|||
158 | $18.String = Exception |
|
|||
159 | $17.AffectedEntity = CustomExceptions |
|
|||
160 | $17.VisibilityMask = VisibilityMask |
|
|||
161 | $17.NamingStyle = PascalCase |
|
|||
162 | $17.IncludeInstanceMembers = True |
|
|||
163 | $17.IncludeStaticEntities = True |
|
|||
164 | $8.NamingRule = $19 |
|
|||
165 | $19.Name = Methods |
|
|||
166 | $19.AffectedEntity = Methods |
|
|||
167 | $19.VisibilityMask = VisibilityMask |
|
|||
168 | $19.NamingStyle = PascalCase |
|
|||
169 | $19.IncludeInstanceMembers = True |
|
|||
170 | $19.IncludeStaticEntities = True |
|
|||
171 | $8.NamingRule = $20 |
|
|||
172 | $20.Name = Static Readonly Fields |
|
|||
173 | $20.AffectedEntity = ReadonlyField |
|
|||
174 | $20.VisibilityMask = Internal, Protected, Public |
|
|||
175 | $20.NamingStyle = CamelCase |
|
|||
176 | $20.IncludeInstanceMembers = False |
|
|||
177 | $20.IncludeStaticEntities = True |
|
|||
178 | $8.NamingRule = $21 |
|
|||
179 | $21.Name = Fields (Non Private) |
|
|||
180 | $21.AffectedEntity = Field |
|
|||
181 | $21.VisibilityMask = Internal, Public |
|
|||
182 | $21.NamingStyle = CamelCase |
|
|||
183 | $21.IncludeInstanceMembers = True |
|
|||
184 | $21.IncludeStaticEntities = True |
|
|||
185 | $8.NamingRule = $22 |
|
|||
186 | $22.Name = ReadOnly Fields (Non Private) |
|
|||
187 | $22.AffectedEntity = ReadonlyField |
|
|||
188 | $22.VisibilityMask = Internal, Public |
|
|||
189 | $22.NamingStyle = CamelCase |
|
|||
190 | $22.IncludeInstanceMembers = True |
|
|||
191 | $22.IncludeStaticEntities = False |
|
|||
192 | $8.NamingRule = $23 |
|
|||
193 | $23.Name = Fields (Private) |
|
|||
194 | $23.RequiredPrefixes = $24 |
|
|||
195 | $24.String = m_ |
|
|||
196 | $23.AffectedEntity = Field, ReadonlyField |
|
|||
197 | $23.VisibilityMask = Private, Protected |
|
|||
198 | $23.NamingStyle = CamelCase |
|
|||
199 | $23.IncludeInstanceMembers = True |
|
|||
200 | $23.IncludeStaticEntities = False |
|
|||
201 | $8.NamingRule = $25 |
|
|||
202 | $25.Name = Static Fields (Private) |
|
|||
203 | $25.RequiredPrefixes = $26 |
|
|||
204 | $26.String = _ |
|
|||
205 | $25.AffectedEntity = Field |
|
|||
206 | $25.VisibilityMask = Private |
|
|||
207 | $25.NamingStyle = CamelCase |
|
|||
208 | $25.IncludeInstanceMembers = False |
|
|||
209 | $25.IncludeStaticEntities = True |
|
|||
210 | $8.NamingRule = $27 |
|
|||
211 | $27.Name = ReadOnly Fields (Private) |
|
|||
212 | $27.RequiredPrefixes = $28 |
|
|||
213 | $28.String = m_ |
|
|||
214 | $27.AffectedEntity = ReadonlyField |
|
|||
215 | $27.VisibilityMask = Private, Protected |
|
|||
216 | $27.NamingStyle = CamelCase |
|
|||
217 | $27.IncludeInstanceMembers = True |
|
|||
218 | $27.IncludeStaticEntities = False |
|
|||
219 | $8.NamingRule = $29 |
|
|||
220 | $29.Name = Constant Fields |
|
|||
221 | $29.AffectedEntity = ConstantField |
|
|||
222 | $29.VisibilityMask = VisibilityMask |
|
|||
223 | $29.NamingStyle = AllUpper |
|
|||
224 | $29.IncludeInstanceMembers = True |
|
|||
225 | $29.IncludeStaticEntities = True |
|
|||
226 | $8.NamingRule = $30 |
|
|||
227 | $30.Name = Properties |
|
|||
228 | $30.AffectedEntity = Property |
|
|||
229 | $30.VisibilityMask = VisibilityMask |
|
|||
230 | $30.NamingStyle = PascalCase |
|
|||
231 | $30.IncludeInstanceMembers = True |
|
|||
232 | $30.IncludeStaticEntities = True |
|
|||
233 | $8.NamingRule = $31 |
|
|||
234 | $31.Name = Events |
|
|||
235 | $31.AffectedEntity = Event |
|
|||
236 | $31.VisibilityMask = VisibilityMask |
|
|||
237 | $31.NamingStyle = PascalCase |
|
|||
238 | $31.IncludeInstanceMembers = True |
|
|||
239 | $31.IncludeStaticEntities = True |
|
|||
240 | $8.NamingRule = $32 |
|
|||
241 | $32.Name = Enum Members |
|
|||
242 | $32.AffectedEntity = EnumMember |
|
|||
243 | $32.VisibilityMask = VisibilityMask |
|
|||
244 | $32.NamingStyle = PascalCase |
|
|||
245 | $32.IncludeInstanceMembers = True |
|
|||
246 | $32.IncludeStaticEntities = True |
|
|||
247 | $8.NamingRule = $33 |
|
|||
248 | $33.Name = Parameters |
|
|||
249 | $33.AffectedEntity = Parameter, LocalVariable |
|
|||
250 | $33.VisibilityMask = VisibilityMask |
|
|||
251 | $33.NamingStyle = CamelCase |
|
|||
252 | $33.IncludeInstanceMembers = True |
|
|||
253 | $33.IncludeStaticEntities = True |
|
|||
254 | $8.NamingRule = $34 |
|
|||
255 | $34.Name = Type Parameters |
|
|||
256 | $34.RequiredPrefixes = $35 |
|
|||
257 | $35.String = T |
|
|||
258 | $34.AffectedEntity = TypeParameter |
|
|||
259 | $34.VisibilityMask = VisibilityMask |
|
|||
260 | $34.NamingStyle = PascalCase |
|
|||
261 | $34.IncludeInstanceMembers = True |
|
|||
262 | $34.IncludeStaticEntities = True |
|
|||
263 | EndGlobalSection |
|
|||
264 | GlobalSection(TestCaseManagementSettings) = postSolution |
|
|||
265 | CategoryFile = Implab.vsmdi |
|
|||
266 | EndGlobalSection |
|
62 | EndGlobalSection | |
267 | GlobalSection(SolutionProperties) = preSolution |
|
63 | GlobalSection(SolutionProperties) = preSolution | |
268 | HideSolutionNode = FALSE |
|
64 | HideSolutionNode = FALSE | |
269 | EndGlobalSection |
|
65 | EndGlobalSection | |
|
66 | GlobalSection(ExtensibilityGlobals) = postSolution | |||
|
67 | SolutionGuid = {36D837FC-4CDD-4AEA-87BF-F130FEB22E02} | |||
|
68 | EndGlobalSection | |||
270 | EndGlobal |
|
69 | EndGlobal |
@@ -1,277 +1,26 | |||||
1 | <?xml version="1.0" encoding="utf-8"?> |
|
1 | <Project Sdk="Microsoft.NET.Sdk"> | |
2 | <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
|
2 | ||
3 | <PropertyGroup> |
|
3 | <PropertyGroup> | |
4 | <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> |
|
4 | <Authors>Sergey Smirnov</Authors> | |
5 | <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> |
|
5 | <Title>Implab library</Title> | |
6 | <ProjectGuid>{F550F1F8-8746-4AD0-9614-855F4C4B7F05}</ProjectGuid> |
|
6 | <Description>Provides some helper clesses like XML serialization helpers, JSON XML reader, | |
7 | <OutputType>Library</OutputType> |
|
7 | JSON pull-parser, ECMA-style promises, lightweight synchonization routines Signal | |
8 | <RootNamespace>Implab</RootNamespace> |
|
8 | and SharedLock, Trace helpers on top of System.Diagnostics, ObjectPool etc. | |
9 | <AssemblyName>Implab</AssemblyName> |
|
9 | </Description> | |
10 | <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> |
|
10 | <Copyright>2012-2018 Sergey Smirnov</Copyright> | |
11 |
< |
|
11 | <Version>3.0.14</Version> | |
12 | <SchemaVersion>2.0</SchemaVersion> |
|
12 | <PackageLicenseUrl>https://bitbucket.org/wozard/implabnet/src/v3/Implab/license.txt</PackageLicenseUrl> | |
13 | </PropertyGroup> |
|
13 | <PackageProjectUrl>https://bitbucket.org/wozard/implabnet</PackageProjectUrl> | |
14 | <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> |
|
14 | <RepositoryUrl>https://bitbucket.org/wozard/implabnet</RepositoryUrl> | |
15 | <DebugSymbols>true</DebugSymbols> |
|
15 | <RepositoryType>mercurial</RepositoryType> | |
16 | <DebugType>full</DebugType> |
|
16 | <PackageTags>IMPLAB;Json pull-parser;Json Xml;async;diagnostics;serialization;</PackageTags> | |
17 | <Optimize>false</Optimize> |
|
17 | <TargetFrameworks>netstandard2.0;net46</TargetFrameworks> | |
18 | <OutputPath>bin\Debug</OutputPath> |
|
18 | <FrameworkPathOverride Condition="'$(TargetFramework)'=='net46' and '$(OSTYPE)'=='linux'">/usr/lib/mono/4.5/</FrameworkPathOverride> | |
19 | <DefineConstants>TRACE;DEBUG;</DefineConstants> |
|
19 | <DefineConstants Condition="'$(TargetFramework)'=='net46'">NETFX_TRACE_BUG;$(DefineConstants)</DefineConstants> | |
20 | <ErrorReport>prompt</ErrorReport> |
|
|||
21 | <WarningLevel>4</WarningLevel> |
|
|||
22 | <ConsolePause>false</ConsolePause> |
|
|||
23 | <RunCodeAnalysis>true</RunCodeAnalysis> |
|
|||
24 | </PropertyGroup> |
|
|||
25 | <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> |
|
|||
26 | <DebugType>full</DebugType> |
|
|||
27 | <Optimize>true</Optimize> |
|
|||
28 | <OutputPath>bin\Release</OutputPath> |
|
|||
29 | <ErrorReport>prompt</ErrorReport> |
|
|||
30 | <WarningLevel>4</WarningLevel> |
|
|||
31 | <ConsolePause>false</ConsolePause> |
|
|||
32 | </PropertyGroup> |
|
20 | </PropertyGroup> | |
33 | <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug 4.5|AnyCPU' "> |
|
21 | ||
34 | <DebugSymbols>true</DebugSymbols> |
|
|||
35 | <DebugType>full</DebugType> |
|
|||
36 | <Optimize>false</Optimize> |
|
|||
37 | <OutputPath>bin\Debug</OutputPath> |
|
|||
38 | <DefineConstants>TRACE;DEBUG;NET_4_5</DefineConstants> |
|
|||
39 | <ErrorReport>prompt</ErrorReport> |
|
|||
40 | <WarningLevel>4</WarningLevel> |
|
|||
41 | <RunCodeAnalysis>true</RunCodeAnalysis> |
|
|||
42 | <ConsolePause>false</ConsolePause> |
|
|||
43 | </PropertyGroup> |
|
|||
44 | <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release 4.5|AnyCPU' "> |
|
|||
45 | <Optimize>true</Optimize> |
|
|||
46 | <OutputPath>bin\Release</OutputPath> |
|
|||
47 | <ErrorReport>prompt</ErrorReport> |
|
|||
48 | <WarningLevel>4</WarningLevel> |
|
|||
49 | <ConsolePause>false</ConsolePause> |
|
|||
50 | <DefineConstants>NET_4_5</DefineConstants> |
|
|||
51 | </PropertyGroup> |
|
|||
52 | <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'DebugMono|AnyCPU' "> |
|
|||
53 | <DebugSymbols>true</DebugSymbols> |
|
|||
54 | <DebugType>full</DebugType> |
|
|||
55 | <Optimize>false</Optimize> |
|
|||
56 | <OutputPath>bin\Debug</OutputPath> |
|
|||
57 | <DefineConstants>TRACE;DEBUG;NET_4_5;MONO</DefineConstants> |
|
|||
58 | <ErrorReport>prompt</ErrorReport> |
|
|||
59 | <WarningLevel>4</WarningLevel> |
|
|||
60 | <RunCodeAnalysis>true</RunCodeAnalysis> |
|
|||
61 | <ConsolePause>false</ConsolePause> |
|
|||
62 | </PropertyGroup> |
|
|||
63 | <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseMono|AnyCPU' "> |
|
|||
64 | <Optimize>true</Optimize> |
|
|||
65 | <OutputPath>bin\Release</OutputPath> |
|
|||
66 | <DefineConstants>NET_4_5;MONO;</DefineConstants> |
|
|||
67 | <ErrorReport>prompt</ErrorReport> |
|
|||
68 | <WarningLevel>4</WarningLevel> |
|
|||
69 | <ConsolePause>false</ConsolePause> |
|
|||
70 | </PropertyGroup> |
|
|||
71 | <ItemGroup> |
|
|||
72 | <Reference Include="System" /> |
|
|||
73 | <Reference Include="System.Xml" /> |
|
|||
74 | <Reference Include="mscorlib" /> |
|
|||
75 | </ItemGroup> |
|
|||
76 | <ItemGroup> |
|
22 | <ItemGroup> | |
77 | <Compile Include="CustomEqualityComparer.cs" /> |
|
23 | <EmbeddedResource Include="src\Xml\json.xsl"/> | |
78 | <Compile Include="Diagnostics\ConsoleTraceListener.cs" /> |
|
|||
79 | <Compile Include="Diagnostics\EventText.cs" /> |
|
|||
80 | <Compile Include="Diagnostics\LogChannel.cs" /> |
|
|||
81 | <Compile Include="Diagnostics\LogicalOperation.cs" /> |
|
|||
82 | <Compile Include="Diagnostics\TextFileListener.cs" /> |
|
|||
83 | <Compile Include="Diagnostics\TraceLog.cs" /> |
|
|||
84 | <Compile Include="Diagnostics\TraceEvent.cs" /> |
|
|||
85 | <Compile Include="Diagnostics\TraceEventType.cs" /> |
|
|||
86 | <Compile Include="ICancellable.cs" /> |
|
|||
87 | <Compile Include="IProgressHandler.cs" /> |
|
|||
88 | <Compile Include="IProgressNotifier.cs" /> |
|
|||
89 | <Compile Include="IPromiseT.cs" /> |
|
|||
90 | <Compile Include="IPromise.cs" /> |
|
|||
91 | <Compile Include="IServiceLocator.cs" /> |
|
|||
92 | <Compile Include="ITaskController.cs" /> |
|
|||
93 | <Compile Include="Parallels\DispatchPool.cs" /> |
|
|||
94 | <Compile Include="Parallels\ArrayTraits.cs" /> |
|
|||
95 | <Compile Include="Parallels\MTQueue.cs" /> |
|
|||
96 | <Compile Include="Parallels\WorkerPool.cs" /> |
|
|||
97 | <Compile Include="ProgressInitEventArgs.cs" /> |
|
|||
98 | <Compile Include="Properties\AssemblyInfo.cs" /> |
|
|||
99 | <Compile Include="Parallels\AsyncPool.cs" /> |
|
|||
100 | <Compile Include="Safe.cs" /> |
|
|||
101 | <Compile Include="ValueEventArgs.cs" /> |
|
|||
102 | <Compile Include="PromiseExtensions.cs" /> |
|
|||
103 | <Compile Include="SyncContextPromise.cs" /> |
|
|||
104 | <Compile Include="Diagnostics\OperationContext.cs" /> |
|
|||
105 | <Compile Include="Diagnostics\TraceContext.cs" /> |
|
|||
106 | <Compile Include="Diagnostics\LogEventArgs.cs" /> |
|
|||
107 | <Compile Include="Diagnostics\LogEventArgsT.cs" /> |
|
|||
108 | <Compile Include="Diagnostics\Extensions.cs" /> |
|
|||
109 | <Compile Include="PromiseEventType.cs" /> |
|
|||
110 | <Compile Include="Parallels\AsyncQueue.cs" /> |
|
|||
111 | <Compile Include="PromiseT.cs" /> |
|
|||
112 | <Compile Include="IDeferred.cs" /> |
|
|||
113 | <Compile Include="IDeferredT.cs" /> |
|
|||
114 | <Compile Include="Promise.cs" /> |
|
|||
115 | <Compile Include="PromiseTransientException.cs" /> |
|
|||
116 | <Compile Include="Parallels\Signal.cs" /> |
|
|||
117 | <Compile Include="Parallels\SharedLock.cs" /> |
|
|||
118 | <Compile Include="Diagnostics\ILogWriter.cs" /> |
|
|||
119 | <Compile Include="Diagnostics\ListenerBase.cs" /> |
|
|||
120 | <Compile Include="Parallels\BlockingQueue.cs" /> |
|
|||
121 | <Compile Include="AbstractEvent.cs" /> |
|
|||
122 | <Compile Include="AbstractPromise.cs" /> |
|
|||
123 | <Compile Include="AbstractPromiseT.cs" /> |
|
|||
124 | <Compile Include="FuncTask.cs" /> |
|
|||
125 | <Compile Include="FuncTaskBase.cs" /> |
|
|||
126 | <Compile Include="FuncTaskT.cs" /> |
|
|||
127 | <Compile Include="ActionChainTaskBase.cs" /> |
|
|||
128 | <Compile Include="ActionChainTask.cs" /> |
|
|||
129 | <Compile Include="ActionChainTaskT.cs" /> |
|
|||
130 | <Compile Include="FuncChainTaskBase.cs" /> |
|
|||
131 | <Compile Include="FuncChainTask.cs" /> |
|
|||
132 | <Compile Include="FuncChainTaskT.cs" /> |
|
|||
133 | <Compile Include="ActionTaskBase.cs" /> |
|
|||
134 | <Compile Include="ActionTask.cs" /> |
|
|||
135 | <Compile Include="ActionTaskT.cs" /> |
|
|||
136 | <Compile Include="ICancellationToken.cs" /> |
|
|||
137 | <Compile Include="SuccessPromise.cs" /> |
|
|||
138 | <Compile Include="SuccessPromiseT.cs" /> |
|
|||
139 | <Compile Include="PromiseAwaiterT.cs" /> |
|
|||
140 | <Compile Include="PromiseAwaiter.cs" /> |
|
|||
141 | <Compile Include="Components\ComponentContainer.cs" /> |
|
|||
142 | <Compile Include="Components\Disposable.cs" /> |
|
|||
143 | <Compile Include="Components\DisposablePool.cs" /> |
|
|||
144 | <Compile Include="Components\ObjectPool.cs" /> |
|
|||
145 | <Compile Include="Components\ServiceLocator.cs" /> |
|
|||
146 | <Compile Include="Components\IInitializable.cs" /> |
|
|||
147 | <Compile Include="TaskController.cs" /> |
|
|||
148 | <Compile Include="Components\App.cs" /> |
|
|||
149 | <Compile Include="Components\IRunnable.cs" /> |
|
|||
150 | <Compile Include="Components\ExecutionState.cs" /> |
|
|||
151 | <Compile Include="Components\RunnableComponent.cs" /> |
|
|||
152 | <Compile Include="Components\IFactory.cs" /> |
|
|||
153 | <Compile Include="Automaton\IAlphabet.cs" /> |
|
|||
154 | <Compile Include="Automaton\ParserException.cs" /> |
|
|||
155 | <Compile Include="Automaton\IndexedAlphabetBase.cs" /> |
|
|||
156 | <Compile Include="Automaton\IAlphabetBuilder.cs" /> |
|
|||
157 | <Compile Include="Automaton\RegularExpressions\AltToken.cs" /> |
|
|||
158 | <Compile Include="Automaton\RegularExpressions\BinaryToken.cs" /> |
|
|||
159 | <Compile Include="Automaton\RegularExpressions\CatToken.cs" /> |
|
|||
160 | <Compile Include="Automaton\RegularExpressions\StarToken.cs" /> |
|
|||
161 | <Compile Include="Automaton\RegularExpressions\SymbolToken.cs" /> |
|
|||
162 | <Compile Include="Automaton\RegularExpressions\EmptyToken.cs" /> |
|
|||
163 | <Compile Include="Automaton\RegularExpressions\Token.cs" /> |
|
|||
164 | <Compile Include="Automaton\RegularExpressions\IVisitor.cs" /> |
|
|||
165 | <Compile Include="Automaton\AutomatonTransition.cs" /> |
|
|||
166 | <Compile Include="Formats\JSON\JSONElementContext.cs" /> |
|
|||
167 | <Compile Include="Formats\JSON\JSONElementType.cs" /> |
|
|||
168 | <Compile Include="Formats\JSON\JSONGrammar.cs" /> |
|
|||
169 | <Compile Include="Formats\JSON\JSONParser.cs" /> |
|
|||
170 | <Compile Include="Formats\JSON\JSONScanner.cs" /> |
|
|||
171 | <Compile Include="Formats\JSON\JsonTokenType.cs" /> |
|
|||
172 | <Compile Include="Formats\JSON\JSONWriter.cs" /> |
|
|||
173 | <Compile Include="Formats\JSON\JSONXmlReader.cs" /> |
|
|||
174 | <Compile Include="Formats\JSON\JSONXmlReaderOptions.cs" /> |
|
|||
175 | <Compile Include="Formats\JSON\StringTranslator.cs" /> |
|
|||
176 | <Compile Include="Automaton\MapAlphabet.cs" /> |
|
|||
177 | <Compile Include="Formats\CharAlphabet.cs" /> |
|
|||
178 | <Compile Include="Formats\ByteAlphabet.cs" /> |
|
|||
179 | <Compile Include="Automaton\IDFATable.cs" /> |
|
|||
180 | <Compile Include="Automaton\IDFATableBuilder.cs" /> |
|
|||
181 | <Compile Include="Automaton\DFATable.cs" /> |
|
|||
182 | <Compile Include="Automaton\RegularExpressions\RegularExpressionVisitor.cs" /> |
|
|||
183 | <Compile Include="Automaton\RegularExpressions\ITaggedDFABuilder.cs" /> |
|
|||
184 | <Compile Include="Formats\TextScanner.cs" /> |
|
|||
185 | <Compile Include="Formats\StringScanner.cs" /> |
|
|||
186 | <Compile Include="Formats\ReaderScanner.cs" /> |
|
|||
187 | <Compile Include="Formats\ScannerContext.cs" /> |
|
|||
188 | <Compile Include="Formats\Grammar.cs" /> |
|
|||
189 | <Compile Include="Automaton\RegularExpressions\EndTokenT.cs" /> |
|
|||
190 | <Compile Include="Automaton\RegularExpressions\EndToken.cs" /> |
|
|||
191 | <Compile Include="Automaton\RegularExpressions\RegularExpressionVisitorT.cs" /> |
|
|||
192 | <Compile Include="Automaton\AutomatonConst.cs" /> |
|
|||
193 | <Compile Include="Automaton\RegularExpressions\RegularDFA.cs" /> |
|
|||
194 | <Compile Include="Components\LazyAndWeak.cs" /> |
|
|||
195 | <Compile Include="AbstractTask.cs" /> |
|
|||
196 | <Compile Include="AbstractTaskT.cs" /> |
|
|||
197 | </ItemGroup> |
|
24 | </ItemGroup> | |
198 | <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> |
|
25 | ||
199 | <ItemGroup /> |
|
26 | </Project> | |
200 | <ProjectExtensions> |
|
|||
201 | <MonoDevelop> |
|
|||
202 | <Properties> |
|
|||
203 | <Policies> |
|
|||
204 | <CSharpFormattingPolicy IndentBlock="True" IndentBraces="False" IndentSwitchSection="False" IndentSwitchCaseSection="True" LabelPositioning="OneLess" NewLinesForBracesInTypes="True" NewLinesForBracesInMethods="True" NewLinesForBracesInProperties="False" NewLinesForBracesInAccessors="False" NewLinesForBracesInAnonymousMethods="False" NewLinesForBracesInControlBlocks="False" NewLinesForBracesInAnonymousTypes="False" NewLinesForBracesInObjectCollectionArrayInitializers="False" NewLinesForBracesInLambdaExpressionBody="False" NewLineForElse="False" NewLineForCatch="False" NewLineForFinally="False" NewLineForMembersInObjectInit="False" NewLineForMembersInAnonymousTypes="False" NewLineForClausesInQuery="False" SpacingAfterMethodDeclarationName="True" SpaceWithinMethodDeclarationParenthesis="False" SpaceBetweenEmptyMethodDeclarationParentheses="False" SpaceAfterMethodCallName="True" SpaceWithinMethodCallParentheses="False" SpaceBetweenEmptyMethodCallParentheses="False" SpaceAfterControlFlowStatementKeyword="True" SpaceWithinExpressionParentheses="False" SpaceWithinCastParentheses="False" SpaceWithinOtherParentheses="False" SpaceAfterCast="False" SpacesIgnoreAroundVariableDeclaration="False" SpaceBeforeOpenSquareBracket="True" SpaceBetweenEmptySquareBrackets="False" SpaceWithinSquareBrackets="False" SpaceAfterColonInBaseTypeDeclaration="True" SpaceAfterComma="True" SpaceAfterDot="False" SpaceAfterSemicolonsInForStatement="True" SpaceBeforeColonInBaseTypeDeclaration="True" SpaceBeforeComma="False" SpaceBeforeDot="False" SpaceBeforeSemicolonsInForStatement="False" SpacingAroundBinaryOperator="Single" WrappingPreserveSingleLine="True" WrappingKeepStatementsOnSingleLine="True" PlaceSystemDirectiveFirst="True" scope="text/x-csharp" /> |
|
|||
205 | <TextStylePolicy FileWidth="120" TabWidth="4" IndentWidth="4" RemoveTrailingWhitespace="True" NoTabsAfterNonTabs="False" TabsToSpaces="True" EolMarker="Unix" scope="text/x-csharp" /> |
|
|||
206 | <DotNetNamingPolicy DirectoryNamespaceAssociation="PrefixedHierarchical" ResourceNamePolicy="MSBuild" /> |
|
|||
207 | <TextStylePolicy FileWidth="120" TabWidth="4" TabsToSpaces="False" IndentWidth="4" RemoveTrailingWhitespace="True" NoTabsAfterNonTabs="False" EolMarker="Native" scope="application/xml" /> |
|
|||
208 | <XmlFormattingPolicy scope="application/xml"> |
|
|||
209 | <DefaultFormat OmitXmlDeclaration="False" NewLineChars="
" IndentContent="True" ContentIndentString="	" AttributesInNewLine="False" MaxAttributesPerLine="10" AttributesIndentString="	" WrapAttributes="False" AlignAttributes="False" AlignAttributeValues="False" QuoteChar=""" SpacesBeforeAssignment="0" SpacesAfterAssignment="0" EmptyLinesBeforeStart="0" EmptyLinesAfterStart="0" EmptyLinesBeforeEnd="0" EmptyLinesAfterEnd="0" /> |
|
|||
210 | </XmlFormattingPolicy> |
|
|||
211 | <TextStylePolicy FileWidth="120" TabWidth="4" TabsToSpaces="False" IndentWidth="4" RemoveTrailingWhitespace="True" NoTabsAfterNonTabs="False" EolMarker="Native" scope="text/plain" /> |
|
|||
212 | <NameConventionPolicy> |
|
|||
213 | <Rules> |
|
|||
214 | <NamingRule Name="Namespaces" AffectedEntity="Namespace" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" /> |
|
|||
215 | <NamingRule Name="Types" AffectedEntity="Class, Struct, Enum, Delegate" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" /> |
|
|||
216 | <NamingRule Name="Interfaces" AffectedEntity="Interface" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True"> |
|
|||
217 | <RequiredPrefixes> |
|
|||
218 | <String>I</String> |
|
|||
219 | </RequiredPrefixes> |
|
|||
220 | </NamingRule> |
|
|||
221 | <NamingRule Name="Attributes" AffectedEntity="CustomAttributes" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True"> |
|
|||
222 | <RequiredSuffixes> |
|
|||
223 | <String>Attribute</String> |
|
|||
224 | </RequiredSuffixes> |
|
|||
225 | </NamingRule> |
|
|||
226 | <NamingRule Name="Event Arguments" AffectedEntity="CustomEventArgs" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True"> |
|
|||
227 | <RequiredSuffixes> |
|
|||
228 | <String>EventArgs</String> |
|
|||
229 | </RequiredSuffixes> |
|
|||
230 | </NamingRule> |
|
|||
231 | <NamingRule Name="Exceptions" AffectedEntity="CustomExceptions" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True"> |
|
|||
232 | <RequiredSuffixes> |
|
|||
233 | <String>Exception</String> |
|
|||
234 | </RequiredSuffixes> |
|
|||
235 | </NamingRule> |
|
|||
236 | <NamingRule Name="Methods" AffectedEntity="Methods" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" /> |
|
|||
237 | <NamingRule Name="Static Readonly Fields" AffectedEntity="ReadonlyField" VisibilityMask="Internal, Protected, Public" NamingStyle="CamelCase" IncludeInstanceMembers="False" IncludeStaticEntities="True" /> |
|
|||
238 | <NamingRule Name="Fields (Non Private)" AffectedEntity="Field" VisibilityMask="Internal, Public" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" /> |
|
|||
239 | <NamingRule Name="ReadOnly Fields (Non Private)" AffectedEntity="ReadonlyField" VisibilityMask="Internal, Public" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="False" /> |
|
|||
240 | <NamingRule Name="Fields (Private)" AffectedEntity="Field, ReadonlyField" VisibilityMask="Private, Protected" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="False"> |
|
|||
241 | <RequiredPrefixes> |
|
|||
242 | <String>m_</String> |
|
|||
243 | </RequiredPrefixes> |
|
|||
244 | </NamingRule> |
|
|||
245 | <NamingRule Name="Static Fields (Private)" AffectedEntity="Field" VisibilityMask="Private" NamingStyle="CamelCase" IncludeInstanceMembers="False" IncludeStaticEntities="True"> |
|
|||
246 | <RequiredPrefixes> |
|
|||
247 | <String>_</String> |
|
|||
248 | </RequiredPrefixes> |
|
|||
249 | </NamingRule> |
|
|||
250 | <NamingRule Name="ReadOnly Fields (Private)" AffectedEntity="ReadonlyField" VisibilityMask="Private, Protected" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="False"> |
|
|||
251 | <RequiredPrefixes> |
|
|||
252 | <String>m_</String> |
|
|||
253 | </RequiredPrefixes> |
|
|||
254 | </NamingRule> |
|
|||
255 | <NamingRule Name="Constant Fields" AffectedEntity="ConstantField" VisibilityMask="VisibilityMask" NamingStyle="AllUpper" IncludeInstanceMembers="True" IncludeStaticEntities="True" /> |
|
|||
256 | <NamingRule Name="Properties" AffectedEntity="Property" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" /> |
|
|||
257 | <NamingRule Name="Events" AffectedEntity="Event" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" /> |
|
|||
258 | <NamingRule Name="Enum Members" AffectedEntity="EnumMember" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" /> |
|
|||
259 | <NamingRule Name="Parameters" AffectedEntity="Parameter, LocalVariable" VisibilityMask="VisibilityMask" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" /> |
|
|||
260 | <NamingRule Name="Type Parameters" AffectedEntity="TypeParameter" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True"> |
|
|||
261 | <RequiredPrefixes> |
|
|||
262 | <String>T</String> |
|
|||
263 | </RequiredPrefixes> |
|
|||
264 | </NamingRule> |
|
|||
265 | </Rules> |
|
|||
266 | </NameConventionPolicy> |
|
|||
267 | </Policies> |
|
|||
268 | </Properties> |
|
|||
269 | </MonoDevelop> |
|
|||
270 | </ProjectExtensions> |
|
|||
271 | <ItemGroup> |
|
|||
272 | <Folder Include="Components\" /> |
|
|||
273 | <Folder Include="Automaton\RegularExpressions\" /> |
|
|||
274 | <Folder Include="Formats\" /> |
|
|||
275 | <Folder Include="Formats\JSON\" /> |
|
|||
276 | </ItemGroup> |
|
|||
277 | </Project> No newline at end of file |
|
@@ -1,300 +1,130 | |||||
1 | using System; |
|
1 | using System; | |
2 | using Implab.Parallels; |
|
2 | using Implab.Parallels; | |
3 | using System.Threading; |
|
3 | using System.Threading; | |
4 | using System.Reflection; |
|
4 | using System.Reflection; | |
|
5 | using System.Diagnostics; | |||
5 |
|
6 | |||
6 | namespace Implab { |
|
7 | namespace Implab { | |
7 | public abstract class AbstractEvent<THandler> : ICancellationToken, ICancellable { |
|
8 | /// <summary> | |
8 |
|
9 | /// Abstract class for creation of custom one-shot thread safe events. | ||
9 | const int UNRESOLVED_SATE = 0; |
|
10 | /// </summary> | |
10 | const int TRANSITIONAL_STATE = 1; |
|
11 | /// <remarks> | |
11 | protected const int SUCCEEDED_STATE = 2; |
|
12 | /// <para> | |
12 | protected const int REJECTED_STATE = 3; |
|
13 | /// An event is something that should happen in the future and the | |
13 | protected const int CANCELLED_STATE = 4; |
|
14 | /// triggering of the event causes execution of some pending actions | |
14 |
|
15 | /// which are formely event handlers. One-shot events occur only once | ||
15 | const int CANCEL_NOT_REQUESTED = 0; |
|
16 | /// and any handler added after the event is triggered should run | |
16 | const int CANCEL_REQUESTING = 1; |
|
17 | /// without a delay. | |
17 | const int CANCEL_REQUESTED = 2; |
|
18 | /// </para> | |
18 |
|
19 | /// <para> | ||
19 | const int RESERVED_HANDLERS_COUNT = 4; |
|
20 | /// The lifecycle of the one-shot event is tipically consists of following | |
20 |
|
21 | /// phases. | ||
21 | int m_state; |
|
22 | /// <list> | |
22 | Exception m_error; |
|
23 | /// <description>Pending state. This is the initial state of the event. Any | |
23 | int m_handlersCount; |
|
24 | /// handler added to the event will be queued for the future execution. | |
|
25 | /// </description> | |||
|
26 | /// <description>Transitional state. This is intermediate state between pending | |||
|
27 | /// and fulfilled states, during this state internal initialization and storing | |||
|
28 | /// of the result occurs. | |||
|
29 | /// </description> | |||
|
30 | /// <description>Fulfilled state. The event contains the result, all queued | |||
|
31 | /// handlers are signalled to run and newly added handlers are executed | |||
|
32 | /// immediatelly. | |||
|
33 | /// </description> | |||
|
34 | /// </list> | |||
|
35 | /// </para> | |||
|
36 | /// </remarks> | |||
|
37 | public abstract class AbstractEvent<THandler> where THandler : class { | |||
|
38 | const int PendingState = 0; | |||
24 |
|
39 | |||
25 | //readonly THandler[] m_handlers = new THandler[RESERVED_HANDLERS_COUNT]; |
|
40 | const int TransitionalState = 1; | |
26 | THandler[] m_handlers; |
|
|||
27 | MTQueue<THandler> m_extraHandlers; |
|
|||
28 | int m_handlerPointer = -1; |
|
|||
29 | int m_handlersCommited; |
|
|||
30 |
|
41 | |||
31 | int m_cancelRequest; |
|
42 | const int ResolvedState = 2; | |
32 | Exception m_cancelationReason; |
|
|||
33 | MTQueue<Action<Exception>> m_cancelationHandlers; |
|
|||
34 |
|
43 | |||
|
44 | volatile int m_state; | |||
35 |
|
45 | |||
36 | #region state managment |
|
46 | THandler m_handler; | |
37 | bool BeginTransit() { |
|
47 | SimpleAsyncQueue<THandler> m_extraHandlers; | |
38 | return UNRESOLVED_SATE == Interlocked.CompareExchange(ref m_state, TRANSITIONAL_STATE, UNRESOLVED_SATE); |
|
|||
39 | } |
|
|||
40 |
|
48 | |||
41 | void CompleteTransit(int state) { |
|
49 | public bool IsResolved { | |
42 | if (TRANSITIONAL_STATE != Interlocked.CompareExchange(ref m_state, state, TRANSITIONAL_STATE)) |
|
50 | get { | |
43 | throw new InvalidOperationException("Can't complete transition when the object isn't in the transitional state"); |
|
51 | return m_state > TransitionalState; | |
44 | } |
|
|||
45 |
|
||||
46 | void WaitTransition() { |
|
|||
47 | while (m_state == TRANSITIONAL_STATE) { |
|
|||
48 | Thread.MemoryBarrier(); |
|
|||
49 | } |
|
52 | } | |
50 | } |
|
53 | } | |
51 |
|
54 | |||
52 | protected bool BeginSetResult() { |
|
55 | #region state managment | |
53 |
|
|
56 | protected bool BeginTransit() { | |
54 | WaitTransition(); |
|
57 | return PendingState == Interlocked.CompareExchange(ref m_state, TransitionalState, PendingState); | |
55 | if (m_state != CANCELLED_STATE) |
|
|||
56 | throw new InvalidOperationException("The promise is already resolved"); |
|
|||
57 | return false; |
|
|||
58 | } |
|
|||
59 | return true; |
|
|||
60 | } |
|
58 | } | |
61 |
|
59 | |||
62 |
protected void |
|
60 | protected void CompleteTransit() { | |
63 | CompleteTransit(SUCCEEDED_STATE); |
|
61 | #if DEBUG | |
|
62 | if (TransitionalState != Interlocked.CompareExchange(ref m_state, ResolvedState, TransitionalState)) | |||
|
63 | throw new InvalidOperationException("Can't complete transition when the object isn't in the transitional state"); | |||
|
64 | #else | |||
|
65 | m_state = ResolvedState; | |||
|
66 | #endif | |||
64 | Signal(); |
|
67 | Signal(); | |
65 | } |
|
68 | } | |
66 |
|
69 | |||
|
70 | protected void WaitTransition() { | |||
|
71 | if (m_state == TransitionalState) { | |||
|
72 | SpinWait spin = new SpinWait(); | |||
|
73 | do { | |||
|
74 | spin.SpinOnce(); | |||
|
75 | } while (m_state == TransitionalState); | |||
|
76 | } | |||
|
77 | } | |||
|
78 | ||||
67 |
|
79 | |||
68 |
|
80 | protected abstract void SignalHandler(THandler handler); | ||
69 | /// <summary> |
|
|||
70 | /// Выполняет обещание, сообщая об ошибке |
|
|||
71 | /// </summary> |
|
|||
72 | /// <remarks> |
|
|||
73 | /// Поскольку обещание должно работать в многопточной среде, при его выполнении сразу несколько потоков |
|
|||
74 | /// могу вернуть ошибку, при этом только первая будет использована в качестве результата, остальные |
|
|||
75 | /// будут проигнорированы. |
|
|||
76 | /// </remarks> |
|
|||
77 | /// <param name="error">Исключение возникшее при выполнении операции</param> |
|
|||
78 | /// <exception cref="InvalidOperationException">Данное обещание уже выполнено</exception> |
|
|||
79 | protected void SetError(Exception error) { |
|
|||
80 | if (BeginTransit()) { |
|
|||
81 | m_error = error; |
|
|||
82 | CompleteTransit(REJECTED_STATE); |
|
|||
83 |
|
||||
84 | Signal(); |
|
|||
85 | } else { |
|
|||
86 | WaitTransition(); |
|
|||
87 | if (m_state == SUCCEEDED_STATE) |
|
|||
88 | throw new InvalidOperationException("The promise is already resolved"); |
|
|||
89 | } |
|
|||
90 | } |
|
|||
91 |
|
||||
92 | /// <summary> |
|
|||
93 | /// Отменяет операцию, если это возможно. |
|
|||
94 | /// </summary> |
|
|||
95 | /// <remarks>Для определения была ли операция отменена следует использовать свойство <see cref="IsCancelled"/>.</remarks> |
|
|||
96 | protected void SetCancelled(Exception reason) { |
|
|||
97 | if (BeginTransit()) { |
|
|||
98 | m_error = reason; |
|
|||
99 | CompleteTransit(CANCELLED_STATE); |
|
|||
100 | Signal(); |
|
|||
101 | } |
|
|||
102 | } |
|
|||
103 |
|
||||
104 | protected abstract void SignalHandler(THandler handler, int signal); |
|
|||
105 |
|
81 | |||
106 | void Signal() { |
|
82 | void Signal() { | |
107 | var hp = m_handlerPointer; |
|
|||
108 | var slot = hp +1 ; |
|
|||
109 | while (slot < m_handlersCommited) { |
|
|||
110 | if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) == hp) { |
|
|||
111 | SignalHandler(m_handlers[slot], m_state); |
|
|||
112 | } |
|
|||
113 | hp = m_handlerPointer; |
|
|||
114 | slot = hp +1 ; |
|
|||
115 | } |
|
|||
116 |
|
||||
117 |
|
||||
118 | if (m_extraHandlers != null) { |
|
|||
119 |
|
|
83 | THandler handler; | |
120 |
|
|
84 | while (TryDequeueHandler(out handler)) | |
121 |
|
|
85 | SignalHandler(handler); | |
122 | } |
|
|||
123 | } |
|
86 | } | |
124 |
|
87 | |||
125 | #endregion |
|
88 | #endregion | |
126 |
|
89 | |||
127 | protected abstract Signal GetResolveSignal(); |
|
|||
128 |
|
||||
129 | #region synchronization traits |
|
|||
130 | protected void WaitResult(int timeout) { |
|
|||
131 | if (!(IsResolved || GetResolveSignal().Wait(timeout))) |
|
|||
132 | throw new TimeoutException(); |
|
|||
133 |
|
||||
134 | switch (m_state) { |
|
|||
135 | case SUCCEEDED_STATE: |
|
|||
136 | return; |
|
|||
137 | case CANCELLED_STATE: |
|
|||
138 | throw new OperationCanceledException("The operation has been cancelled", m_error); |
|
|||
139 | case REJECTED_STATE: |
|
|||
140 | throw new TargetInvocationException(m_error); |
|
|||
141 | default: |
|
|||
142 | throw new ApplicationException(String.Format("The promise state {0} is invalid", m_state)); |
|
|||
143 | } |
|
|||
144 | } |
|
|||
145 | #endregion |
|
|||
146 |
|
||||
147 | #region handlers managment |
|
90 | #region handlers managment | |
148 |
|
91 | |||
149 | protected void AddHandler(THandler handler) { |
|
92 | protected void AddHandler(THandler handler) { | |
150 |
|
93 | |||
151 |
if ( |
|
94 | if (IsResolved) { | |
152 | // the promise is in the resolved state, just invoke the handler |
|
95 | // the promise is in the resolved state, just invoke the handler | |
153 |
SignalHandler(handler |
|
96 | SignalHandler(handler); | |
154 | } else { |
|
97 | } else { | |
155 | var slot = Interlocked.Increment(ref m_handlersCount) - 1; |
|
98 | EnqueueHandler(handler); | |
156 |
|
||||
157 | if (slot < RESERVED_HANDLERS_COUNT) { |
|
|||
158 |
|
||||
159 | if (slot == 0) { |
|
|||
160 | m_handlers = new THandler[RESERVED_HANDLERS_COUNT]; |
|
|||
161 | } else { |
|
|||
162 | while (m_handlers == null) |
|
|||
163 | Thread.MemoryBarrier(); |
|
|||
164 | } |
|
|||
165 |
|
||||
166 | m_handlers[slot] = handler; |
|
|||
167 |
|
||||
168 | while (slot != Interlocked.CompareExchange(ref m_handlersCommited, slot + 1, slot)) { |
|
|||
169 | } |
|
|||
170 |
|
99 | |||
171 | if (m_state > 1) { |
|
100 | if (IsResolved && TryDequeueHandler(out handler)) | |
172 | do { |
|
|||
173 | var hp = m_handlerPointer; |
|
|||
174 | slot = hp + 1; |
|
|||
175 | if (slot < m_handlersCommited) { |
|
|||
176 | if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) != hp) |
|
|||
177 | continue; |
|
|||
178 | SignalHandler(m_handlers[slot], m_state); |
|
|||
179 | } |
|
|||
180 | break; |
|
|||
181 | } while(true); |
|
|||
182 | } |
|
|||
183 | } else { |
|
|||
184 | if (slot == RESERVED_HANDLERS_COUNT) { |
|
|||
185 | m_extraHandlers = new MTQueue<THandler>(); |
|
|||
186 | } else { |
|
|||
187 | while (m_extraHandlers == null) |
|
|||
188 | Thread.MemoryBarrier(); |
|
|||
189 | } |
|
|||
190 |
|
||||
191 | m_extraHandlers.Enqueue(handler); |
|
|||
192 |
|
||||
193 | if (m_state > 1 && m_extraHandlers.TryDequeue(out handler)) |
|
|||
194 | // if the promise have been resolved while we was adding the handler to the queue |
|
101 | // if the promise have been resolved while we was adding the handler to the queue | |
195 | // we can't guarantee that someone is still processing it |
|
102 | // we can't guarantee that someone is still processing it | |
196 | // therefore we need to fetch a handler from the queue and execute it |
|
103 | // therefore we need to fetch a handler from the queue and execute it | |
197 | // note that fetched handler may be not the one that we have added |
|
104 | // note that fetched handler may be not the one that we have added | |
198 | // even we can fetch no handlers at all :) |
|
105 | // even we can fetch no handlers at all :) | |
199 |
|
|
106 | SignalHandler(handler); | |
200 |
|
|
107 | } | |
201 | } |
|
108 | ||
202 | } |
|
109 | } | |
203 |
|
110 | |||
204 | #endregion |
|
111 | void EnqueueHandler(THandler handler) { | |
205 |
|
112 | if (Interlocked.CompareExchange(ref m_handler, handler, null) != null) { | ||
206 | #region IPromise implementation |
|
113 | if (m_extraHandlers == null) | |
207 |
|
114 | // compare-exchange will protect from loosing already created queue | ||
208 | public bool IsResolved { |
|
115 | Interlocked.CompareExchange(ref m_extraHandlers, new SimpleAsyncQueue<THandler>(), null); | |
209 | get { |
|
116 | m_extraHandlers.Enqueue(handler); | |
210 | Thread.MemoryBarrier(); |
|
|||
211 | return m_state > 1; |
|
|||
212 | } |
|
|||
213 | } |
|
|||
214 |
|
||||
215 | public bool IsCancelled { |
|
|||
216 | get { |
|
|||
217 | Thread.MemoryBarrier(); |
|
|||
218 | return m_state == CANCELLED_STATE; |
|
|||
219 | } |
|
|||
220 | } |
|
|||
221 |
|
||||
222 | #endregion |
|
|||
223 |
|
||||
224 | public Exception Error { |
|
|||
225 | get { |
|
|||
226 | return m_error; |
|
|||
227 | } |
|
117 | } | |
228 | } |
|
118 | } | |
229 |
|
119 | |||
230 | public bool CancelOperationIfRequested() { |
|
120 | bool TryDequeueHandler(out THandler handler) { | |
231 | if (IsCancellationRequested) { |
|
121 | handler = Interlocked.Exchange(ref m_handler, null); | |
232 | CancelOperation(CancellationReason); |
|
122 | if (handler != null) | |
233 | return true; |
|
123 | return true; | |
234 | } |
|
124 | return m_extraHandlers != null && m_extraHandlers.TryDequeue(out handler); | |
235 | return false; |
|
|||
236 | } |
|
|||
237 |
|
||||
238 | public virtual void CancelOperation(Exception reason) { |
|
|||
239 | SetCancelled(reason); |
|
|||
240 | } |
|
|||
241 |
|
||||
242 | public void CancellationRequested(Action<Exception> handler) { |
|
|||
243 | Safe.ArgumentNotNull(handler, "handler"); |
|
|||
244 | if (IsCancellationRequested) |
|
|||
245 | handler(CancellationReason); |
|
|||
246 |
|
||||
247 | if (m_cancelationHandlers == null) |
|
|||
248 | Interlocked.CompareExchange(ref m_cancelationHandlers, new MTQueue<Action<Exception>>(), null); |
|
|||
249 |
|
||||
250 | m_cancelationHandlers.Enqueue(handler); |
|
|||
251 |
|
||||
252 | if (IsCancellationRequested && m_cancelationHandlers.TryDequeue(out handler)) |
|
|||
253 | // TryDeque implies MemoryBarrier() |
|
|||
254 | handler(m_cancelationReason); |
|
|||
255 | } |
|
|||
256 |
|
||||
257 | public bool IsCancellationRequested { |
|
|||
258 | get { |
|
|||
259 | do { |
|
|||
260 | if (m_cancelRequest == CANCEL_NOT_REQUESTED) |
|
|||
261 | return false; |
|
|||
262 | if (m_cancelRequest == CANCEL_REQUESTED) |
|
|||
263 | return true; |
|
|||
264 | Thread.MemoryBarrier(); |
|
|||
265 | } while(true); |
|
|||
266 | } |
|
|||
267 | } |
|
|||
268 |
|
||||
269 | public Exception CancellationReason { |
|
|||
270 | get { |
|
|||
271 | do { |
|
|||
272 | Thread.MemoryBarrier(); |
|
|||
273 | } while(m_cancelRequest == CANCEL_REQUESTING); |
|
|||
274 |
|
||||
275 | return m_cancelationReason; |
|
|||
276 | } |
|
|||
277 | } |
|
|||
278 |
|
||||
279 | #region ICancellable implementation |
|
|||
280 |
|
||||
281 | public void Cancel() { |
|
|||
282 | Cancel(null); |
|
|||
283 | } |
|
|||
284 |
|
||||
285 | public void Cancel(Exception reason) { |
|
|||
286 | if (CANCEL_NOT_REQUESTED == Interlocked.CompareExchange(ref m_cancelRequest, CANCEL_REQUESTING, CANCEL_NOT_REQUESTED)) { |
|
|||
287 | m_cancelationReason = reason; |
|
|||
288 | m_cancelRequest = CANCEL_REQUESTED; |
|
|||
289 | if (m_cancelationHandlers != null) { |
|
|||
290 | Action<Exception> handler; |
|
|||
291 | while (m_cancelationHandlers.TryDequeue(out handler)) |
|
|||
292 | handler(m_cancelationReason); |
|
|||
293 | } |
|
|||
294 | } |
|
|||
295 | } |
|
125 | } | |
296 |
|
126 | |||
297 | #endregion |
|
127 | #endregion | |
298 | } |
|
128 | } | |
299 | } |
|
129 | } | |
300 |
|
130 |
@@ -1,9 +1,9 | |||||
1 |
|
1 | |||
2 | namespace Implab.Automaton { |
|
2 | namespace Implab.Automaton { | |
3 | public static class AutomatonConst { |
|
3 | public static class AutomatonConst { | |
4 |
public const int U |
|
4 | public const int UnreachableState = -1; | |
5 |
|
5 | |||
6 |
public const int U |
|
6 | public const int UnclassifiedInput = 0; | |
7 | } |
|
7 | } | |
8 | } |
|
8 | } | |
9 |
|
9 |
@@ -1,33 +1,41 | |||||
1 | using System; |
|
1 | using System; | |
2 |
|
2 | |||
3 | namespace Implab.Automaton { |
|
3 | namespace Implab.Automaton { | |
4 |
public |
|
4 | public class AutomatonTransition : IEquatable<AutomatonTransition> { | |
5 | public readonly int s1; |
|
5 | public readonly int s1; | |
6 | public readonly int s2; |
|
6 | public readonly int s2; | |
7 | public readonly int edge; |
|
7 | public readonly int edge; | |
8 |
|
8 | |||
9 | public AutomatonTransition(int s1, int s2, int edge) { |
|
9 | public AutomatonTransition(int s1, int s2, int edge) { | |
10 | this.s1 = s1; |
|
10 | this.s1 = s1; | |
11 | this.s2 = s2; |
|
11 | this.s2 = s2; | |
12 | this.edge = edge; |
|
12 | this.edge = edge; | |
13 | } |
|
13 | } | |
14 |
|
14 | |||
15 |
|
15 | |||
16 | #region IEquatable implementation |
|
16 | #region IEquatable implementation | |
17 | public bool Equals(AutomatonTransition other) { |
|
17 | public bool Equals(AutomatonTransition other) { | |
18 | return other.s1 == s1 && other.s2 == s2 && other.edge == edge ; |
|
18 | return other.s1 == s1 && other.s2 == s2 && other.edge == edge ; | |
19 | } |
|
19 | } | |
20 | #endregion |
|
20 | #endregion | |
21 |
|
21 | |||
22 | public override bool Equals(object obj) { |
|
22 | public override bool Equals(object obj) { | |
23 | if (obj is AutomatonTransition) |
|
23 | if (obj is AutomatonTransition) | |
24 | return Equals((AutomatonTransition)obj); |
|
24 | return Equals((AutomatonTransition)obj); | |
25 | return base.Equals(obj); |
|
25 | return base.Equals(obj); | |
26 | } |
|
26 | } | |
27 |
|
27 | |||
28 | public override int GetHashCode() { |
|
28 | public override int GetHashCode() { | |
29 | return s1 + s2 + edge; |
|
29 | return s1 + s2 + edge; | |
30 | } |
|
30 | } | |
|
31 | ||||
|
32 | public static bool operator == (AutomatonTransition rv, AutomatonTransition lv) { | |||
|
33 | return rv.Equals(lv); | |||
|
34 | } | |||
|
35 | ||||
|
36 | public static bool operator !=(AutomatonTransition rv, AutomatonTransition lv) { | |||
|
37 | return rv.Equals(lv); | |||
|
38 | } | |||
31 | } |
|
39 | } | |
32 | } |
|
40 | } | |
33 |
|
41 |
@@ -1,348 +1,348 | |||||
1 | using Implab; |
|
1 | using Implab; | |
2 | using System; |
|
2 | using System; | |
3 | using System.Collections.Generic; |
|
3 | using System.Collections.Generic; | |
4 | using System.Linq; |
|
4 | using System.Linq; | |
5 | using System.Diagnostics; |
|
5 | using System.Diagnostics; | |
6 | using System.IO; |
|
6 | using System.IO; | |
7 | using System.CodeDom.Compiler; |
|
7 | using System.CodeDom.Compiler; | |
8 | using System.CodeDom; |
|
8 | using System.CodeDom; | |
9 |
|
9 | |||
10 | namespace Implab.Automaton { |
|
10 | namespace Implab.Automaton { | |
11 | public class DFATable : IDFATableBuilder { |
|
11 | public class DFATable : IDFATableBuilder { | |
12 | int m_stateCount; |
|
12 | int m_stateCount; | |
13 | int m_symbolCount; |
|
13 | int m_symbolCount; | |
14 | int m_initialState; |
|
14 | int m_initialState; | |
15 |
|
15 | |||
16 | readonly HashSet<int> m_finalStates = new HashSet<int>(); |
|
16 | readonly HashSet<int> m_finalStates = new HashSet<int>(); | |
17 | readonly HashSet<AutomatonTransition> m_transitions = new HashSet<AutomatonTransition>(); |
|
17 | readonly HashSet<AutomatonTransition> m_transitions = new HashSet<AutomatonTransition>(); | |
18 |
|
18 | |||
19 |
|
19 | |||
20 | #region IDFADefinition implementation |
|
20 | #region IDFADefinition implementation | |
21 |
|
21 | |||
22 | public bool IsFinalState(int s) { |
|
22 | public bool IsFinalState(int s) { | |
23 |
Safe.ArgumentInRange(s |
|
23 | Safe.ArgumentInRange(s >= 0 && s < m_stateCount, nameof(s)); | |
24 |
|
24 | |||
25 | return m_finalStates.Contains(s); |
|
25 | return m_finalStates.Contains(s); | |
26 | } |
|
26 | } | |
27 |
|
27 | |||
28 | public IEnumerable<int> FinalStates { |
|
28 | public IEnumerable<int> FinalStates { | |
29 | get { |
|
29 | get { | |
30 | return m_finalStates; |
|
30 | return m_finalStates; | |
31 | } |
|
31 | } | |
32 | } |
|
32 | } | |
33 |
|
33 | |||
34 | public int StateCount { |
|
34 | public int StateCount { | |
35 | get { return m_stateCount; } |
|
35 | get { return m_stateCount; } | |
36 | } |
|
36 | } | |
37 |
|
37 | |||
38 | public int AlphabetSize { |
|
38 | public int AlphabetSize { | |
39 | get { return m_symbolCount; } |
|
39 | get { return m_symbolCount; } | |
40 | } |
|
40 | } | |
41 |
|
41 | |||
42 | public int InitialState { |
|
42 | public int InitialState { | |
43 | get { return m_initialState; } |
|
43 | get { return m_initialState; } | |
44 | } |
|
44 | } | |
45 |
|
45 | |||
46 | #endregion |
|
46 | #endregion | |
47 |
|
47 | |||
48 | public void SetInitialState(int s) { |
|
48 | public void SetInitialState(int s) { | |
49 |
Safe.Argument |
|
49 | Safe.ArgumentInRange(s >= 0, nameof(s)); | |
50 | m_stateCount = Math.Max(m_stateCount, s + 1); |
|
50 | m_stateCount = Math.Max(m_stateCount, s + 1); | |
51 | m_initialState = s; |
|
51 | m_initialState = s; | |
52 | } |
|
52 | } | |
53 |
|
53 | |||
54 | public void MarkFinalState(int state) { |
|
54 | public void MarkFinalState(int state) { | |
55 | m_stateCount = Math.Max(m_stateCount, state + 1); |
|
55 | m_stateCount = Math.Max(m_stateCount, state + 1); | |
56 | m_finalStates.Add(state); |
|
56 | m_finalStates.Add(state); | |
57 | } |
|
57 | } | |
58 |
|
58 | |||
59 | public void Add(AutomatonTransition item) { |
|
59 | public void Add(AutomatonTransition item) { | |
60 |
Safe.ArgumentAssert(item.s1 >= 0, |
|
60 | Safe.ArgumentAssert(item.s1 >= 0, nameof(item)); | |
61 |
Safe.ArgumentAssert(item.s2 >= 0, |
|
61 | Safe.ArgumentAssert(item.s2 >= 0, nameof(item)); | |
62 |
Safe.ArgumentAssert(item.edge >= 0, |
|
62 | Safe.ArgumentAssert(item.edge >= 0, nameof(item)); | |
63 |
|
63 | |||
64 | m_stateCount = Math.Max(m_stateCount, Math.Max(item.s1, item.s2) + 1); |
|
64 | m_stateCount = Math.Max(m_stateCount, Math.Max(item.s1, item.s2) + 1); | |
65 | m_symbolCount = Math.Max(m_symbolCount, item.edge + 1); |
|
65 | m_symbolCount = Math.Max(m_symbolCount, item.edge + 1); | |
66 |
|
66 | |||
67 | m_transitions.Add(item); |
|
67 | m_transitions.Add(item); | |
68 | } |
|
68 | } | |
69 |
|
69 | |||
70 | public void Clear() { |
|
70 | public void Clear() { | |
71 | m_stateCount = 0; |
|
71 | m_stateCount = 0; | |
72 | m_symbolCount = 0; |
|
72 | m_symbolCount = 0; | |
73 | m_finalStates.Clear(); |
|
73 | m_finalStates.Clear(); | |
74 | m_transitions.Clear(); |
|
74 | m_transitions.Clear(); | |
75 | } |
|
75 | } | |
76 |
|
76 | |||
77 | public bool Contains(AutomatonTransition item) { |
|
77 | public bool Contains(AutomatonTransition item) { | |
78 | return m_transitions.Contains(item); |
|
78 | return m_transitions.Contains(item); | |
79 | } |
|
79 | } | |
80 |
|
80 | |||
81 | public void CopyTo(AutomatonTransition[] array, int arrayIndex) { |
|
81 | public void CopyTo(AutomatonTransition[] array, int arrayIndex) { | |
82 | m_transitions.CopyTo(array, arrayIndex); |
|
82 | m_transitions.CopyTo(array, arrayIndex); | |
83 | } |
|
83 | } | |
84 |
|
84 | |||
85 | public bool Remove(AutomatonTransition item) { |
|
85 | public bool Remove(AutomatonTransition item) { | |
86 | return m_transitions.Remove(item); |
|
86 | return m_transitions.Remove(item); | |
87 | } |
|
87 | } | |
88 |
|
88 | |||
89 | public int Count { |
|
89 | public int Count { | |
90 | get { |
|
90 | get { | |
91 | return m_transitions.Count; |
|
91 | return m_transitions.Count; | |
92 | } |
|
92 | } | |
93 | } |
|
93 | } | |
94 |
|
94 | |||
95 | public bool IsReadOnly { |
|
95 | public bool IsReadOnly { | |
96 | get { |
|
96 | get { | |
97 | return false; |
|
97 | return false; | |
98 | } |
|
98 | } | |
99 | } |
|
99 | } | |
100 |
|
100 | |||
101 | public IEnumerator<AutomatonTransition> GetEnumerator() { |
|
101 | public IEnumerator<AutomatonTransition> GetEnumerator() { | |
102 | return m_transitions.GetEnumerator(); |
|
102 | return m_transitions.GetEnumerator(); | |
103 | } |
|
103 | } | |
104 |
|
104 | |||
105 | System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { |
|
105 | System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { | |
106 | return GetEnumerator(); |
|
106 | return GetEnumerator(); | |
107 | } |
|
107 | } | |
108 |
|
108 | |||
109 | public void AddSymbol(int symbol) { |
|
109 | public void AddSymbol(int symbol) { | |
110 | Safe.ArgumentAssert(symbol >= 0, "symbol"); |
|
110 | Safe.ArgumentAssert(symbol >= 0, "symbol"); | |
111 | m_symbolCount = Math.Max(symbol + 1, m_symbolCount); |
|
111 | m_symbolCount = Math.Max(symbol + 1, m_symbolCount); | |
112 | } |
|
112 | } | |
113 |
|
113 | |||
114 | public int[,] CreateTransitionTable() { |
|
114 | public int[,] CreateTransitionTable() { | |
115 | var table = new int[StateCount,AlphabetSize]; |
|
115 | var table = new int[StateCount,AlphabetSize]; | |
116 |
|
116 | |||
117 | for (int i = 0; i < StateCount; i++) |
|
117 | for (int i = 0; i < StateCount; i++) | |
118 | for (int j = 0; j < AlphabetSize; j++) |
|
118 | for (int j = 0; j < AlphabetSize; j++) | |
119 |
table[i, j] = AutomatonConst.U |
|
119 | table[i, j] = AutomatonConst.UnreachableState; | |
120 |
|
120 | |||
121 | foreach (var t in this) |
|
121 | foreach (var t in this) | |
122 | table[t.s1,t.edge] = t.s2; |
|
122 | table[t.s1,t.edge] = (byte)t.s2; | |
123 |
|
123 | |||
124 | return table; |
|
124 | return table; | |
125 | } |
|
125 | } | |
126 |
|
126 | |||
127 | public bool[] CreateFinalStateTable() { |
|
127 | public bool[] CreateFinalStateTable() { | |
128 | var table = new bool[StateCount]; |
|
128 | var table = new bool[StateCount]; | |
129 |
|
129 | |||
130 | foreach (var s in FinalStates) |
|
130 | foreach (var s in FinalStates) | |
131 | table[s] = true; |
|
131 | table[s] = true; | |
132 |
|
132 | |||
133 | return table; |
|
133 | return table; | |
134 | } |
|
134 | } | |
135 |
|
135 | |||
136 | /// <summary>Формирует множества конечных состояний перед началом работы алгоритма минимизации.</summary> |
|
136 | /// <summary>Формирует множества конечных состояний перед началом работы алгоритма минимизации.</summary> | |
137 | /// <remarks> |
|
137 | /// <remarks> | |
138 | /// В процессе построения минимального автомата требуется разделить множество состояний, |
|
138 | /// В процессе построения минимального автомата требуется разделить множество состояний, | |
139 | /// на два подмножества - конечные состояния и все остальные, после чего эти подмножества |
|
139 | /// на два подмножества - конечные состояния и все остальные, после чего эти подмножества | |
140 | /// будут резделены на более мелкие. Иногда требуется гарантировать различия конечных сосотяний, |
|
140 | /// будут резделены на более мелкие. Иногда требуется гарантировать различия конечных сосотяний, | |
141 | /// для этого необходимо переопределить даннцю фукнцию, для получения множеств конечных состояний. |
|
141 | /// для этого необходимо переопределить даннцю фукнцию, для получения множеств конечных состояний. | |
142 | /// </remarks> |
|
142 | /// </remarks> | |
143 | /// <returns>The final states.</returns> |
|
143 | /// <returns>The final states.</returns> | |
144 | protected virtual IEnumerable<HashSet<int>> SplitFinalStates(IEnumerable<int> states) { |
|
144 | protected virtual IEnumerable<HashSet<int>> SplitFinalStates(IEnumerable<int> states) { | |
145 | return new [] { new HashSet<int>(states) }; |
|
145 | return new [] { new HashSet<int>(states) }; | |
146 | } |
|
146 | } | |
147 |
|
147 | |||
148 | protected void Optimize( |
|
148 | protected void Optimize( | |
149 | IDFATableBuilder optimalDFA, |
|
149 | IDFATableBuilder optimalDFA, | |
150 | IDictionary<int,int> alphabetMap, |
|
150 | IDictionary<int,int> alphabetMap, | |
151 | IDictionary<int,int> stateMap |
|
151 | IDictionary<int,int> stateMap | |
152 | ) { |
|
152 | ) { | |
153 | Safe.ArgumentNotNull(optimalDFA, "dfa"); |
|
153 | Safe.ArgumentNotNull(optimalDFA, "dfa"); | |
154 | Safe.ArgumentNotNull(alphabetMap, "alphabetMap"); |
|
154 | Safe.ArgumentNotNull(alphabetMap, "alphabetMap"); | |
155 | Safe.ArgumentNotNull(stateMap, "stateMap"); |
|
155 | Safe.ArgumentNotNull(stateMap, "stateMap"); | |
156 |
|
156 | |||
157 |
|
157 | |||
158 | var setComparer = new CustomEqualityComparer<HashSet<int>>( |
|
158 | var setComparer = new CustomEqualityComparer<HashSet<int>>( | |
159 | (x, y) => x.SetEquals(y), |
|
159 | (x, y) => x.SetEquals(y), | |
160 | s => s.Sum(x => x.GetHashCode()) |
|
160 | s => s.Sum(x => x.GetHashCode()) | |
161 | ); |
|
161 | ); | |
162 |
|
162 | |||
163 | var optimalStates = new HashSet<HashSet<int>>(setComparer); |
|
163 | var optimalStates = new HashSet<HashSet<int>>(setComparer); | |
164 | var queue = new HashSet<HashSet<int>>(setComparer); |
|
164 | var queue = new HashSet<HashSet<int>>(setComparer); | |
165 |
|
165 | |||
166 | optimalStates.Add(new HashSet<int>(FinalStates)); |
|
166 | optimalStates.Add(new HashSet<int>(FinalStates)); | |
167 |
|
167 | |||
168 | var state = new HashSet<int>( |
|
168 | var state = new HashSet<int>( | |
169 | Enumerable |
|
169 | Enumerable | |
170 | .Range(0, m_stateCount) |
|
170 | .Range(0, m_stateCount) | |
171 | .Where(i => !m_finalStates.Contains(i)) |
|
171 | .Where(i => !m_finalStates.Contains(i)) | |
172 | ); |
|
172 | ); | |
173 |
|
173 | |||
174 | optimalStates.Add(state); |
|
174 | optimalStates.Add(state); | |
175 | queue.Add(state); |
|
175 | queue.Add(state); | |
176 |
|
176 | |||
177 | var rmap = m_transitions |
|
177 | var rmap = m_transitions | |
178 | .GroupBy(t => t.s2) |
|
178 | .GroupBy(t => t.s2) | |
179 | .ToDictionary( |
|
179 | .ToDictionary( | |
180 | g => g.Key, // s2 |
|
180 | g => g.Key, // s2 | |
181 | g => g.ToLookup(t => t.edge, t => t.s1)//.ToDictionary(p => p.Key) |
|
181 | g => g.ToLookup(t => t.edge, t => t.s1)//.ToDictionary(p => p.Key) | |
182 | ); |
|
182 | ); | |
183 |
|
183 | |||
184 | while (queue.Count > 0) { |
|
184 | while (queue.Count > 0) { | |
185 | var stateA = queue.First(); |
|
185 | var stateA = queue.First(); | |
186 | queue.Remove(stateA); |
|
186 | queue.Remove(stateA); | |
187 |
|
187 | |||
188 | for (int c = 0; c < m_symbolCount; c++) { |
|
188 | for (int c = 0; c < m_symbolCount; c++) { | |
189 | var stateX = new HashSet<int>(); |
|
189 | var stateX = new HashSet<int>(); | |
190 | foreach(var a in stateA.Where(rmap.ContainsKey)) |
|
190 | foreach(var a in stateA.Where(rmap.ContainsKey)) | |
191 | stateX.UnionWith(rmap[a][c]); // all states from wich the symbol 'c' leads to the state 'a' |
|
191 | stateX.UnionWith(rmap[a][c]); // all states from wich the symbol 'c' leads to the state 'a' | |
192 |
|
192 | |||
193 | var tmp = optimalStates.ToArray(); |
|
193 | var tmp = optimalStates.ToArray(); | |
194 | foreach (var stateY in tmp) { |
|
194 | foreach (var stateY in tmp) { | |
195 | var stateR1 = new HashSet<int>(stateY); |
|
195 | var stateR1 = new HashSet<int>(stateY); | |
196 | var stateR2 = new HashSet<int>(stateY); |
|
196 | var stateR2 = new HashSet<int>(stateY); | |
197 |
|
197 | |||
198 | stateR1.IntersectWith(stateX); |
|
198 | stateR1.IntersectWith(stateX); | |
199 | stateR2.ExceptWith(stateX); |
|
199 | stateR2.ExceptWith(stateX); | |
200 |
|
200 | |||
201 | if (stateR1.Count > 0 && stateR2.Count > 0) { |
|
201 | if (stateR1.Count > 0 && stateR2.Count > 0) { | |
202 |
|
202 | |||
203 |
|
203 | |||
204 | optimalStates.Remove(stateY); |
|
204 | optimalStates.Remove(stateY); | |
205 | optimalStates.Add(stateR1); |
|
205 | optimalStates.Add(stateR1); | |
206 | optimalStates.Add(stateR2); |
|
206 | optimalStates.Add(stateR2); | |
207 |
|
207 | |||
208 | if (queue.Contains(stateY)) { |
|
208 | if (queue.Contains(stateY)) { | |
209 | queue.Remove(stateY); |
|
209 | queue.Remove(stateY); | |
210 | queue.Add(stateR1); |
|
210 | queue.Add(stateR1); | |
211 | queue.Add(stateR2); |
|
211 | queue.Add(stateR2); | |
212 | } else { |
|
212 | } else { | |
213 | queue.Add(stateR1.Count <= stateR2.Count ? stateR1 : stateR2); |
|
213 | queue.Add(stateR1.Count <= stateR2.Count ? stateR1 : stateR2); | |
214 | } |
|
214 | } | |
215 | } |
|
215 | } | |
216 | } |
|
216 | } | |
217 | } |
|
217 | } | |
218 | } |
|
218 | } | |
219 |
|
219 | |||
220 | // дополнительно разбиваем конечные состояния |
|
220 | // дополнительно разбиваем конечные состояния | |
221 | foreach (var final in optimalStates.Where(s => s.Overlaps(m_finalStates)).ToArray()) { |
|
221 | foreach (var final in optimalStates.Where(s => s.Overlaps(m_finalStates)).ToArray()) { | |
222 | optimalStates.Remove(final); |
|
222 | optimalStates.Remove(final); | |
223 | foreach (var split in SplitFinalStates(final)) |
|
223 | foreach (var split in SplitFinalStates(final)) | |
224 | optimalStates.Add(split); |
|
224 | optimalStates.Add(split); | |
225 | } |
|
225 | } | |
226 |
|
226 | |||
227 |
|
227 | |||
228 | // карта получения оптимального состояния по соотвествующему ему простому состоянию |
|
228 | // карта получения оптимального состояния по соотвествующему ему простому состоянию | |
229 | var nextState = 0; |
|
229 | var nextState = 0; | |
230 | foreach (var item in optimalStates) { |
|
230 | foreach (var item in optimalStates) { | |
231 | var id = nextState++; |
|
231 | var id = nextState++; | |
232 | foreach (var s in item) |
|
232 | foreach (var s in item) | |
233 | stateMap[s] = id; |
|
233 | stateMap[s] = id; | |
234 | } |
|
234 | } | |
235 |
|
235 | |||
236 | // получаем минимальный алфавит |
|
236 | // получаем минимальный алфавит | |
237 | // входные символы не различимы, если Move(s,a1) == Move(s,a2), для любого s |
|
237 | // входные символы не различимы, если Move(s,a1) == Move(s,a2), для любого s | |
238 | // для этого используем алгоритм кластеризации, сначала |
|
238 | // для этого используем алгоритм кластеризации, сначала | |
239 | // считаем, что все символы не различимы |
|
239 | // считаем, что все символы не различимы | |
240 |
|
240 | |||
241 | var minClasses = new HashSet<HashSet<int>>(setComparer); |
|
241 | var minClasses = new HashSet<HashSet<int>>(setComparer); | |
242 | var alphaQueue = new Queue<HashSet<int>>(); |
|
242 | var alphaQueue = new Queue<HashSet<int>>(); | |
243 | alphaQueue.Enqueue(new HashSet<int>(Enumerable.Range(0,AlphabetSize))); |
|
243 | alphaQueue.Enqueue(new HashSet<int>(Enumerable.Range(0,AlphabetSize))); | |
244 |
|
244 | |||
245 | // для всех состояний, будем проверять каждый класс на различимость, |
|
245 | // для всех состояний, будем проверять каждый класс на различимость, | |
246 | // т.е. символы различимы, если они приводят к разным состояниям |
|
246 | // т.е. символы различимы, если они приводят к разным состояниям | |
247 | for (int s = 0 ; s < optimalStates.Count; s++) { |
|
247 | for (int s = 0 ; s < optimalStates.Count; s++) { | |
248 | var newQueue = new Queue<HashSet<int>>(); |
|
248 | var newQueue = new Queue<HashSet<int>>(); | |
249 |
|
249 | |||
250 | foreach (var A in alphaQueue) { |
|
250 | foreach (var A in alphaQueue) { | |
251 | // классы из одного символа делить бесполезно, переводим их сразу в |
|
251 | // классы из одного символа делить бесполезно, переводим их сразу в | |
252 | // результирующий алфавит |
|
252 | // результирующий алфавит | |
253 | if (A.Count == 1) { |
|
253 | if (A.Count == 1) { | |
254 | minClasses.Add(A); |
|
254 | minClasses.Add(A); | |
255 | continue; |
|
255 | continue; | |
256 | } |
|
256 | } | |
257 |
|
257 | |||
258 | // различаем классы символов, которые переводят в различные оптимальные состояния |
|
258 | // различаем классы символов, которые переводят в различные оптимальные состояния | |
259 | // optimalState -> alphaClass |
|
259 | // optimalState -> alphaClass | |
260 | var classes = new Dictionary<int, HashSet<int>>(); |
|
260 | var classes = new Dictionary<int, HashSet<int>>(); | |
261 |
|
261 | |||
262 | foreach (var term in A) { |
|
262 | foreach (var term in A) { | |
263 | // ищем все переходы класса по символу term |
|
263 | // ищем все переходы класса по символу term | |
264 | var s2 = m_transitions.Where(t => stateMap[t.s1] == s && t.edge == term).Select(t => stateMap[t.s2]).DefaultIfEmpty(-1).First(); |
|
264 | var s2 = m_transitions.Where(t => stateMap[t.s1] == s && t.edge == term).Select(t => stateMap[t.s2]).DefaultIfEmpty(-1).First(); | |
265 |
|
265 | |||
266 | HashSet<int> a2; |
|
266 | HashSet<int> a2; | |
267 | if (!classes.TryGetValue(s2, out a2)) { |
|
267 | if (!classes.TryGetValue(s2, out a2)) { | |
268 | a2 = new HashSet<int>(); |
|
268 | a2 = new HashSet<int>(); | |
269 | newQueue.Enqueue(a2); |
|
269 | newQueue.Enqueue(a2); | |
270 | classes[s2] = a2; |
|
270 | classes[s2] = a2; | |
271 | } |
|
271 | } | |
272 | a2.Add(term); |
|
272 | a2.Add(term); | |
273 | } |
|
273 | } | |
274 | } |
|
274 | } | |
275 |
|
275 | |||
276 | if (newQueue.Count == 0) |
|
276 | if (newQueue.Count == 0) | |
277 | break; |
|
277 | break; | |
278 | alphaQueue = newQueue; |
|
278 | alphaQueue = newQueue; | |
279 | } |
|
279 | } | |
280 |
|
280 | |||
281 | // после окончания работы алгоритма в очереди останутся минимальные различимые классы |
|
281 | // после окончания работы алгоритма в очереди останутся минимальные различимые классы | |
282 | // входных символов |
|
282 | // входных символов | |
283 | foreach (var A in alphaQueue) |
|
283 | foreach (var A in alphaQueue) | |
284 | minClasses.Add(A); |
|
284 | minClasses.Add(A); | |
285 |
|
285 | |||
286 | // построение отображения алфавитов входных символов. |
|
286 | // построение отображения алфавитов входных символов. | |
287 | // поскольку символ DFAConst.UNCLASSIFIED_INPUT может иметь |
|
287 | // поскольку символ DFAConst.UNCLASSIFIED_INPUT может иметь | |
288 | // специальное значение, тогда сохраним минимальный класс, |
|
288 | // специальное значение, тогда сохраним минимальный класс, | |
289 | // содержащий этот символ на томже месте. |
|
289 | // содержащий этот символ на томже месте. | |
290 |
|
290 | |||
291 | var nextCls = 0; |
|
291 | var nextCls = 0; | |
292 | foreach (var item in minClasses) { |
|
292 | foreach (var item in minClasses) { | |
293 |
if (nextCls == AutomatonConst.U |
|
293 | if (nextCls == AutomatonConst.UnclassifiedInput) | |
294 | nextCls++; |
|
294 | nextCls++; | |
295 |
|
295 | |||
296 | // сохраняем DFAConst.UNCLASSIFIED_INPUT |
|
296 | // сохраняем DFAConst.UNCLASSIFIED_INPUT | |
297 |
var cls = item.Contains(AutomatonConst.U |
|
297 | var cls = item.Contains(AutomatonConst.UnclassifiedInput) ? AutomatonConst.UnclassifiedInput : nextCls++; | |
298 | optimalDFA.AddSymbol(cls); |
|
298 | optimalDFA.AddSymbol(cls); | |
299 |
|
299 | |||
300 | foreach (var a in item) |
|
300 | foreach (var a in item) | |
301 | alphabetMap[a] = cls; |
|
301 | alphabetMap[a] = cls; | |
302 | } |
|
302 | } | |
303 |
|
303 | |||
304 | // построение автомата |
|
304 | // построение автомата | |
305 | optimalDFA.SetInitialState(stateMap[m_initialState]); |
|
305 | optimalDFA.SetInitialState(stateMap[m_initialState]); | |
306 |
|
306 | |||
307 | foreach (var sf in m_finalStates.Select(s => stateMap[s]).Distinct()) |
|
307 | foreach (var sf in m_finalStates.Select(s => stateMap[s]).Distinct()) | |
308 | optimalDFA.MarkFinalState(sf); |
|
308 | optimalDFA.MarkFinalState(sf); | |
309 |
|
309 | |||
310 | foreach (var t in m_transitions.Select(t => new AutomatonTransition(stateMap[t.s1],stateMap[t.s2],alphabetMap[t.edge])).Distinct()) |
|
310 | foreach (var t in m_transitions.Select(t => new AutomatonTransition(stateMap[t.s1],stateMap[t.s2],alphabetMap[t.edge])).Distinct()) | |
311 | optimalDFA.Add(t); |
|
311 | optimalDFA.Add(t); | |
312 | } |
|
312 | } | |
313 |
|
313 | |||
314 | protected string PrintDFA<TInput, TState>(IAlphabet<TInput> inputAlphabet, IAlphabet<TState> stateAlphabet) { |
|
314 | /*protected string PrintDFA<TInput, TState>(IAlphabet<TInput> inputAlphabet, IAlphabet<TState> stateAlphabet) { | |
315 | Safe.ArgumentNotNull(inputAlphabet, "inputAlphabet"); |
|
315 | Safe.ArgumentNotNull(inputAlphabet, "inputAlphabet"); | |
316 | Safe.ArgumentNotNull(stateAlphabet, "stateAlphabet"); |
|
316 | Safe.ArgumentNotNull(stateAlphabet, "stateAlphabet"); | |
317 |
|
|
317 | ||
318 | var data = new List<string>(); |
|
318 | var data = new List<string>(); | |
319 |
|
|
319 | ||
320 | data.Add("digraph dfa {"); |
|
320 | data.Add("digraph dfa {"); | |
321 |
|
|
321 | ||
322 | foreach (var final in m_finalStates) |
|
322 | foreach (var final in m_finalStates) | |
323 | data.Add(String.Format("{0} [shape=box];",String.Join("", stateAlphabet.GetSymbols(final)))); |
|
323 | data.Add(String.Format("{0} [shape=box];",String.Join("", stateAlphabet.GetSymbols(final)))); | |
324 |
|
|
324 | ||
325 | foreach (var t in m_transitions) |
|
325 | foreach (var t in m_transitions) | |
326 | data.Add(String.Format( |
|
326 | data.Add(String.Format( | |
327 | "{0} -> {2} [label={1}];", |
|
327 | "{0} -> {2} [label={1}];", | |
328 | String.Join("", stateAlphabet.GetSymbols(t.s1)), |
|
328 | String.Join("", stateAlphabet.GetSymbols(t.s1)), | |
329 |
ToLiteral(ToLiteral(String.Join("", t.edge == AutomatonConst.U |
|
329 | ToLiteral(ToLiteral(String.Join("", t.edge == AutomatonConst.UnclassifiedInput ? new [] { "@" } : inputAlphabet.GetSymbols(t.edge).Select(x => x.ToString())))), | |
330 | String.Join("", stateAlphabet.GetSymbols(t.s2)) |
|
330 | String.Join("", stateAlphabet.GetSymbols(t.s2)) | |
331 | )); |
|
331 | )); | |
332 | data.Add("}"); |
|
332 | data.Add("}"); | |
333 | return String.Join("\n", data); |
|
333 | return String.Join("\n", data); | |
334 | } |
|
334 | } | |
335 |
|
|
335 | ||
336 | static string ToLiteral(string input) |
|
336 | static string ToLiteral(string input) | |
337 | { |
|
337 | { | |
338 | using (var writer = new StringWriter()) |
|
338 | using (var writer = new StringWriter()) | |
339 | { |
|
339 | { | |
340 | using (var provider = CodeDomProvider.CreateProvider("CSharp")) |
|
340 | using (var provider = CodeDomProvider.CreateProvider("CSharp")) | |
341 | { |
|
341 | { | |
342 | provider.GenerateCodeFromExpression(new CodePrimitiveExpression(input), writer, null); |
|
342 | provider.GenerateCodeFromExpression(new CodePrimitiveExpression(input), writer, null); | |
343 | return writer.ToString(); |
|
343 | return writer.ToString(); | |
344 | } |
|
344 | } | |
345 | } |
|
345 | } | |
|
346 | }*/ | |||
346 |
|
|
347 | } | |
347 | } |
|
348 | } | |
348 | } |
|
1 | NO CONTENT: file renamed from Implab/Automaton/IAlphabet.cs to Implab/src/Automaton/IAlphabet.cs |
|
NO CONTENT: file renamed from Implab/Automaton/IAlphabet.cs to Implab/src/Automaton/IAlphabet.cs |
1 | NO CONTENT: file renamed from Implab/Automaton/IAlphabetBuilder.cs to Implab/src/Automaton/IAlphabetBuilder.cs |
|
NO CONTENT: file renamed from Implab/Automaton/IAlphabetBuilder.cs to Implab/src/Automaton/IAlphabetBuilder.cs |
1 | NO CONTENT: file renamed from Implab/Automaton/IDFATable.cs to Implab/src/Automaton/IDFATable.cs |
|
NO CONTENT: file renamed from Implab/Automaton/IDFATable.cs to Implab/src/Automaton/IDFATable.cs |
1 | NO CONTENT: file renamed from Implab/Automaton/IDFATableBuilder.cs to Implab/src/Automaton/IDFATableBuilder.cs |
|
NO CONTENT: file renamed from Implab/Automaton/IDFATableBuilder.cs to Implab/src/Automaton/IDFATableBuilder.cs |
1 | NO CONTENT: file renamed from Implab/Automaton/IndexedAlphabetBase.cs to Implab/src/Automaton/IndexedAlphabetBase.cs |
|
NO CONTENT: file renamed from Implab/Automaton/IndexedAlphabetBase.cs to Implab/src/Automaton/IndexedAlphabetBase.cs |
@@ -1,84 +1,84 | |||||
1 | using System; |
|
1 | using System; | |
2 | using System.Collections.Generic; |
|
2 | using System.Collections.Generic; | |
3 | using System.Linq; |
|
3 | using System.Linq; | |
4 |
|
4 | |||
5 | namespace Implab.Automaton { |
|
5 | namespace Implab.Automaton { | |
6 | public class MapAlphabet<T> : IAlphabetBuilder<T> { |
|
6 | public class MapAlphabet<T> : IAlphabetBuilder<T> { | |
7 | readonly Dictionary<T,int> m_map; |
|
7 | readonly Dictionary<T,int> m_map; | |
8 | int m_nextCls; |
|
8 | int m_nextCls; | |
9 | readonly bool m_supportUnclassified; |
|
9 | readonly bool m_supportUnclassified; | |
10 |
|
10 | |||
11 | public MapAlphabet(bool supportUnclassified, IEqualityComparer<T> comparer) { |
|
11 | public MapAlphabet(bool supportUnclassified, IEqualityComparer<T> comparer) { | |
12 | m_map = comparer != null ? new Dictionary<T, int>(comparer) : new Dictionary<T,int>(); |
|
12 | m_map = comparer != null ? new Dictionary<T, int>(comparer) : new Dictionary<T,int>(); | |
13 | m_supportUnclassified = supportUnclassified; |
|
13 | m_supportUnclassified = supportUnclassified; | |
14 | m_nextCls = supportUnclassified ? 1 : 0; |
|
14 | m_nextCls = supportUnclassified ? 1 : 0; | |
15 | } |
|
15 | } | |
16 |
|
16 | |||
17 | #region IAlphabetBuilder implementation |
|
17 | #region IAlphabetBuilder implementation | |
18 |
|
18 | |||
19 | public int DefineSymbol(T symbol) { |
|
19 | public int DefineSymbol(T symbol) { | |
20 | int cls; |
|
20 | int cls; | |
21 | return m_map.TryGetValue(symbol, out cls) ? cls : DefineSymbol(symbol, m_nextCls); |
|
21 | return m_map.TryGetValue(symbol, out cls) ? cls : DefineSymbol(symbol, m_nextCls); | |
22 | } |
|
22 | } | |
23 |
|
23 | |||
24 | public int DefineSymbol(T symbol, int cls) { |
|
24 | public int DefineSymbol(T symbol, int cls) { | |
25 | Safe.ArgumentAssert(cls >= 0, "cls"); |
|
25 | Safe.ArgumentAssert(cls >= 0, "cls"); | |
26 |
|
26 | |||
27 | m_nextCls = Math.Max(cls + 1, m_nextCls); |
|
27 | m_nextCls = Math.Max(cls + 1, m_nextCls); | |
28 | m_map.Add(symbol, cls); |
|
28 | m_map.Add(symbol, cls); | |
29 | return cls; |
|
29 | return cls; | |
30 | } |
|
30 | } | |
31 |
|
31 | |||
32 | public int DefineClass(IEnumerable<T> symbols) { |
|
32 | public int DefineClass(IEnumerable<T> symbols) { | |
33 | return DefineClass(symbols, m_nextCls); |
|
33 | return DefineClass(symbols, m_nextCls); | |
34 | } |
|
34 | } | |
35 |
|
35 | |||
36 | public int DefineClass(IEnumerable<T> symbols, int cls) { |
|
36 | public int DefineClass(IEnumerable<T> symbols, int cls) { | |
37 | Safe.ArgumentAssert(cls >= 0, "cls"); |
|
37 | Safe.ArgumentAssert(cls >= 0, "cls"); | |
38 | Safe.ArgumentNotNull(symbols, "symbols"); |
|
38 | Safe.ArgumentNotNull(symbols, "symbols"); | |
39 |
|
39 | |||
40 | m_nextCls = Math.Max(cls + 1, m_nextCls); |
|
40 | m_nextCls = Math.Max(cls + 1, m_nextCls); | |
41 |
|
41 | |||
42 | foreach (var symbol in symbols) |
|
42 | foreach (var symbol in symbols) | |
43 | m_map[symbol] = cls; |
|
43 | m_map[symbol] = cls; | |
44 | return cls; |
|
44 | return cls; | |
45 | } |
|
45 | } | |
46 |
|
46 | |||
47 | #endregion |
|
47 | #endregion | |
48 |
|
48 | |||
49 | #region IAlphabet implementation |
|
49 | #region IAlphabet implementation | |
50 |
|
50 | |||
51 | public int Translate(T symbol) { |
|
51 | public int Translate(T symbol) { | |
52 | int cls; |
|
52 | int cls; | |
53 | if (m_map.TryGetValue(symbol, out cls)) |
|
53 | if (m_map.TryGetValue(symbol, out cls)) | |
54 | return cls; |
|
54 | return cls; | |
55 | if (!m_supportUnclassified) |
|
55 | if (!m_supportUnclassified) | |
56 | throw new ArgumentOutOfRangeException("symbol", "The specified symbol isn't in the alphabet"); |
|
56 | throw new ArgumentOutOfRangeException("symbol", "The specified symbol isn't in the alphabet"); | |
57 |
return AutomatonConst.U |
|
57 | return AutomatonConst.UnclassifiedInput; | |
58 | } |
|
58 | } | |
59 |
|
59 | |||
60 | public int Count { |
|
60 | public int Count { | |
61 | get { |
|
61 | get { | |
62 | return m_nextCls; |
|
62 | return m_nextCls; | |
63 | } |
|
63 | } | |
64 | } |
|
64 | } | |
65 |
|
65 | |||
66 | public bool Contains(T symbol) { |
|
66 | public bool Contains(T symbol) { | |
67 | return m_supportUnclassified || m_map.ContainsKey(symbol); |
|
67 | return m_supportUnclassified || m_map.ContainsKey(symbol); | |
68 | } |
|
68 | } | |
69 |
|
69 | |||
70 |
|
70 | |||
71 | public IEnumerable<T> GetSymbols(int cls) { |
|
71 | public IEnumerable<T> GetSymbols(int cls) { | |
72 | Safe.ArgumentAssert(!m_supportUnclassified || cls > 0, "cls"); |
|
72 | Safe.ArgumentAssert(!m_supportUnclassified || cls > 0, "cls"); | |
73 | return m_map.Where(p => p.Value == cls).Select(p => p.Key); |
|
73 | return m_map.Where(p => p.Value == cls).Select(p => p.Key); | |
74 | } |
|
74 | } | |
75 | #endregion |
|
75 | #endregion | |
76 |
|
76 | |||
77 | public IEnumerable<KeyValuePair<T,int>> Mappings { |
|
77 | public IEnumerable<KeyValuePair<T,int>> Mappings { | |
78 | get { |
|
78 | get { | |
79 | return m_map; |
|
79 | return m_map; | |
80 | } |
|
80 | } | |
81 | } |
|
81 | } | |
82 | } |
|
82 | } | |
83 | } |
|
83 | } | |
84 |
|
84 |
1 | NO CONTENT: file renamed from Implab/Automaton/ParserException.cs to Implab/src/Automaton/ParserException.cs |
|
NO CONTENT: file renamed from Implab/Automaton/ParserException.cs to Implab/src/Automaton/ParserException.cs |
1 | NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/AltToken.cs to Implab/src/Automaton/RegularExpressions/AltToken.cs |
|
NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/AltToken.cs to Implab/src/Automaton/RegularExpressions/AltToken.cs |
1 | NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/BinaryToken.cs to Implab/src/Automaton/RegularExpressions/BinaryToken.cs |
|
NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/BinaryToken.cs to Implab/src/Automaton/RegularExpressions/BinaryToken.cs |
1 | NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/CatToken.cs to Implab/src/Automaton/RegularExpressions/CatToken.cs |
|
NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/CatToken.cs to Implab/src/Automaton/RegularExpressions/CatToken.cs |
1 | NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/EmptyToken.cs to Implab/src/Automaton/RegularExpressions/EmptyToken.cs |
|
NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/EmptyToken.cs to Implab/src/Automaton/RegularExpressions/EmptyToken.cs |
1 | NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/EndToken.cs to Implab/src/Automaton/RegularExpressions/EndToken.cs |
|
NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/EndToken.cs to Implab/src/Automaton/RegularExpressions/EndToken.cs |
1 | NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/EndTokenT.cs to Implab/src/Automaton/RegularExpressions/EndTokenT.cs |
|
NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/EndTokenT.cs to Implab/src/Automaton/RegularExpressions/EndTokenT.cs |
1 | NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/ITaggedDFABuilder.cs to Implab/src/Automaton/RegularExpressions/ITaggedDFABuilder.cs |
|
NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/ITaggedDFABuilder.cs to Implab/src/Automaton/RegularExpressions/ITaggedDFABuilder.cs |
1 | NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/IVisitor.cs to Implab/src/Automaton/RegularExpressions/IVisitor.cs |
|
NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/IVisitor.cs to Implab/src/Automaton/RegularExpressions/IVisitor.cs |
1 | NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/RegularDFA.cs to Implab/src/Automaton/RegularExpressions/RegularDFA.cs |
|
NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/RegularDFA.cs to Implab/src/Automaton/RegularExpressions/RegularDFA.cs | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/RegularExpressionVisitor.cs to Implab/src/Automaton/RegularExpressions/RegularExpressionVisitor.cs |
|
NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/RegularExpressionVisitor.cs to Implab/src/Automaton/RegularExpressions/RegularExpressionVisitor.cs | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/RegularExpressionVisitorT.cs to Implab/src/Automaton/RegularExpressions/RegularExpressionVisitorT.cs |
|
NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/RegularExpressionVisitorT.cs to Implab/src/Automaton/RegularExpressions/RegularExpressionVisitorT.cs |
1 | NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/StarToken.cs to Implab/src/Automaton/RegularExpressions/StarToken.cs |
|
NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/StarToken.cs to Implab/src/Automaton/RegularExpressions/StarToken.cs |
1 | NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/SymbolToken.cs to Implab/src/Automaton/RegularExpressions/SymbolToken.cs |
|
NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/SymbolToken.cs to Implab/src/Automaton/RegularExpressions/SymbolToken.cs |
1 | NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/Token.cs to Implab/src/Automaton/RegularExpressions/Token.cs |
|
NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/Token.cs to Implab/src/Automaton/RegularExpressions/Token.cs |
1 | NO CONTENT: file renamed from Implab/Components/Disposable.cs to Implab/src/Components/Disposable.cs |
|
NO CONTENT: file renamed from Implab/Components/Disposable.cs to Implab/src/Components/Disposable.cs | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from Implab/Components/DisposablePool.cs to Implab/src/Components/DisposablePool.cs |
|
NO CONTENT: file renamed from Implab/Components/DisposablePool.cs to Implab/src/Components/DisposablePool.cs | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from Implab/Components/ExecutionState.cs to Implab/src/Components/ExecutionState.cs |
|
NO CONTENT: file renamed from Implab/Components/ExecutionState.cs to Implab/src/Components/ExecutionState.cs | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from Implab/Components/IFactory.cs to Implab/src/Components/IFactory.cs |
|
NO CONTENT: file renamed from Implab/Components/IFactory.cs to Implab/src/Components/IFactory.cs |
1 | NO CONTENT: file renamed from Implab/Components/IInitializable.cs to Implab/src/Components/IInitializable.cs |
|
NO CONTENT: file renamed from Implab/Components/IInitializable.cs to Implab/src/Components/IInitializable.cs | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from Implab/Components/IRunnable.cs to Implab/src/Components/IRunnable.cs |
|
NO CONTENT: file renamed from Implab/Components/IRunnable.cs to Implab/src/Components/IRunnable.cs | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from Implab/Components/LazyAndWeak.cs to Implab/src/Components/LazyAndWeak.cs |
|
NO CONTENT: file renamed from Implab/Components/LazyAndWeak.cs to Implab/src/Components/LazyAndWeak.cs | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from Implab/Components/ObjectPool.cs to Implab/src/Components/ObjectPool.cs |
|
NO CONTENT: file renamed from Implab/Components/ObjectPool.cs to Implab/src/Components/ObjectPool.cs | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from Implab/Components/ServiceLocator.cs to Implab/src/Components/ServiceLocator.cs |
|
NO CONTENT: file renamed from Implab/Components/ServiceLocator.cs to Implab/src/Components/ServiceLocator.cs | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from Implab/CustomEqualityComparer.cs to Implab/src/CustomEqualityComparer.cs |
|
NO CONTENT: file renamed from Implab/CustomEqualityComparer.cs to Implab/src/CustomEqualityComparer.cs |
1 | NO CONTENT: file renamed from Implab/Formats/ByteAlphabet.cs to Implab/src/Formats/ByteAlphabet.cs |
|
NO CONTENT: file renamed from Implab/Formats/ByteAlphabet.cs to Implab/src/Formats/ByteAlphabet.cs |
1 | NO CONTENT: file renamed from Implab/Formats/CharAlphabet.cs to Implab/src/Formats/CharAlphabet.cs |
|
NO CONTENT: file renamed from Implab/Formats/CharAlphabet.cs to Implab/src/Formats/CharAlphabet.cs | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from Implab/Formats/Grammar.cs to Implab/src/Formats/Grammar.cs |
|
NO CONTENT: file renamed from Implab/Formats/Grammar.cs to Implab/src/Formats/Grammar.cs | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from Implab/Formats/JSON/JSONElementContext.cs to Implab/src/Formats/Json/JsonElementContext.cs |
|
NO CONTENT: file renamed from Implab/Formats/JSON/JSONElementContext.cs to Implab/src/Formats/Json/JsonElementContext.cs | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from Implab/Formats/JSON/JSONElementType.cs to Implab/src/Formats/Json/JsonElementType.cs |
|
NO CONTENT: file renamed from Implab/Formats/JSON/JSONElementType.cs to Implab/src/Formats/Json/JsonElementType.cs | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from Implab/Formats/JSON/JSONGrammar.cs to Implab/src/Formats/Json/JsonGrammar.cs |
|
NO CONTENT: file renamed from Implab/Formats/JSON/JSONGrammar.cs to Implab/src/Formats/Json/JsonGrammar.cs | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from Implab/Formats/JSON/JSONParser.cs to Implab/src/Formats/Json/JsonReader.cs |
|
NO CONTENT: file renamed from Implab/Formats/JSON/JSONParser.cs to Implab/src/Formats/Json/JsonReader.cs | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from Implab/Formats/JSON/JSONScanner.cs to Implab/src/Formats/Json/JsonScanner.cs |
|
NO CONTENT: file renamed from Implab/Formats/JSON/JSONScanner.cs to Implab/src/Formats/Json/JsonScanner.cs | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from Implab/Formats/JSON/JsonTokenType.cs to Implab/src/Formats/Json/JsonTokenType.cs |
|
NO CONTENT: file renamed from Implab/Formats/JSON/JsonTokenType.cs to Implab/src/Formats/Json/JsonTokenType.cs | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from Implab/Formats/JSON/JSONWriter.cs to Implab/src/Formats/Json/JsonWriter.cs |
|
NO CONTENT: file renamed from Implab/Formats/JSON/JSONWriter.cs to Implab/src/Formats/Json/JsonWriter.cs | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from Implab/Formats/JSON/StringTranslator.cs to Implab/src/Formats/Json/StringTranslator.cs |
|
NO CONTENT: file renamed from Implab/Formats/JSON/StringTranslator.cs to Implab/src/Formats/Json/StringTranslator.cs | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from Implab/IPromise.cs to Implab/src/IPromise.cs |
|
NO CONTENT: file renamed from Implab/IPromise.cs to Implab/src/IPromise.cs | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from Implab/IPromiseT.cs to Implab/src/IPromiseT.cs |
|
NO CONTENT: file renamed from Implab/IPromiseT.cs to Implab/src/IPromiseT.cs | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from Implab/Parallels/AsyncQueue.cs to Implab/src/Parallels/AsyncQueue.cs |
|
NO CONTENT: file renamed from Implab/Parallels/AsyncQueue.cs to Implab/src/Parallels/AsyncQueue.cs | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from Implab/Parallels/BlockingQueue.cs to Implab/src/Parallels/BlockingQueue.cs |
|
NO CONTENT: file renamed from Implab/Parallels/BlockingQueue.cs to Implab/src/Parallels/BlockingQueue.cs | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from Implab/Parallels/DispatchPool.cs to Implab/src/Parallels/DispatchPool.cs |
|
NO CONTENT: file renamed from Implab/Parallels/DispatchPool.cs to Implab/src/Parallels/DispatchPool.cs |
1 | NO CONTENT: file renamed from Implab/Parallels/SharedLock.cs to Implab/src/Parallels/SharedLock.cs |
|
NO CONTENT: file renamed from Implab/Parallels/SharedLock.cs to Implab/src/Parallels/SharedLock.cs |
1 | NO CONTENT: file renamed from Implab/Parallels/Signal.cs to Implab/src/Parallels/Signal.cs |
|
NO CONTENT: file renamed from Implab/Parallels/Signal.cs to Implab/src/Parallels/Signal.cs |
1 | NO CONTENT: file renamed from Implab/PromiseExtensions.cs to Implab/src/PromiseExtensions.cs |
|
NO CONTENT: file renamed from Implab/PromiseExtensions.cs to Implab/src/PromiseExtensions.cs | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from Implab/PromiseTransientException.cs to Implab/src/PromiseTransientException.cs |
|
NO CONTENT: file renamed from Implab/PromiseTransientException.cs to Implab/src/PromiseTransientException.cs |
1 | NO CONTENT: file renamed from Implab/Safe.cs to Implab/src/Safe.cs |
|
NO CONTENT: file renamed from Implab/Safe.cs to Implab/src/Safe.cs | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
This diff has been collapsed as it changes many lines, (863 lines changed) Show them Hide them |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed, binary diff hidden |
|
NO CONTENT: file was removed, binary diff hidden |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed, binary diff hidden |
|
NO CONTENT: file was removed, binary diff hidden |
1 | NO CONTENT: file was removed, binary diff hidden |
|
NO CONTENT: file was removed, binary diff hidden |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed, binary diff hidden |
|
NO CONTENT: file was removed, binary diff hidden |
1 | NO CONTENT: file was removed, binary diff hidden |
|
NO CONTENT: file was removed, binary diff hidden |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed, binary diff hidden |
|
NO CONTENT: file was removed, binary diff hidden |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed, binary diff hidden |
|
NO CONTENT: file was removed, binary diff hidden |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed, binary diff hidden |
|
NO CONTENT: file was removed, binary diff hidden |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed, binary diff hidden |
|
NO CONTENT: file was removed, binary diff hidden |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed, binary diff hidden |
|
NO CONTENT: file was removed, binary diff hidden |
1 | NO CONTENT: file was removed, binary diff hidden |
|
NO CONTENT: file was removed, binary diff hidden |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
General Comments 3
ok, latest stable version should be in default
Pull request merged and closed