##// END OF EJS Templates
Closed
Pull request !2 Created on Tue, 02 Feb 2021 11:50:08, by
  • 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
@@ -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
@@ -0,0 +1,37
1 using System;
2 using System.Threading.Tasks;
3
4 namespace Implab.Components {
5 /// <summary>
6 /// An interface for asynchronous components.
7 /// </summary>
8 /// <remarks>
9 /// <para>
10 /// Асинхронные компоненты не предназначены для одновременного использования несколькими клиентами,
11 /// однако существуют внутренние процессы, изменяющее состояние компонент без участия клиента.
12 /// Данный интерфейс определяет протокол взаимодействия с компонентой, при которм компоненте
13 /// посылаются сигналы от клиента, в ответ на которые компонента меняет свойство <see cref="Completion"/>,
14 /// данное свойство содержит в себе новую задачу, выполняемую компонентой и данное свойство
15 /// может измениться только при получении нового сигнала от клиента.
16 /// </para>
17 /// <para>
18 /// В дополнение к <see cref="Completion"/> компонента может определять другие свойства, в
19 /// которых будет передаваться информация о результате выполнения операции.
20 /// </para>
21 /// <para>
22 /// Особое внимание следует уделить реализации <see cref="IDisposable"/>, который по своей природе
23 /// синхронный, данное правило безусловно можно нарушить, но тогда могут возникнуть проблемы с
24 /// тем, что ресурсы еще не освободились, а ход программы продолжается, что приведет к ошибкам,
25 /// например при попытке получить ресуср другим объектом, либо при заврешении программы.
26 /// </para>
27 /// <seealso href="https://blog.stephencleary.com/2013/01/async-oop-0-introduction.html"/>
28 /// </remarks>
29 public interface IAsyncComponent {
30 /// <summary>
31 /// The result of the last started operation. This property reflects
32 /// only the result of the last started operation and therefore should
33 /// change only if a new operation is initiated.
34 /// </summary>
35 Task Completion { get; }
36 }
37 } No newline at end of file
@@ -0,0 +1,13
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6
7 namespace Implab.Components {
8 public interface IServiceLocator: IServiceProvider {
9 T GetService<T>();
10 bool TryGetService<T>(out T service);
11 bool TryGetService (Type serviceType, out object service);
12 }
13 }
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
@@ -18,3 +18,12 MonoPlay/obj/
18 18 Implab.Test/Implab.Format.Test/bin/
19 19 Implab.Test/Implab.Format.Test/obj/
20 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 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"?>
2 <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 <PropertyGroup>
4 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
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 />
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>
17 5 </PropertyGroup>
18 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
19 <DebugSymbols>true</DebugSymbols>
20 <DebugType>full</DebugType>
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>
6
7 <PropertyGroup Condition="'$(OSTYPE)'=='windows'">
8 <TargetFrameworks>netcoreapp2.0;net46</TargetFrameworks>
36 9 </PropertyGroup>
37 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug 4.5|AnyCPU' ">
38 <DebugSymbols>true</DebugSymbols>
39 <DebugType>full</DebugType>
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>
10
11 <PropertyGroup>
12 <IsPackable>false</IsPackable>
46 13 </PropertyGroup>
47 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release 4.5|AnyCPU' ">
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>
14
56 15 <ItemGroup>
57 <Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
58 <Reference Include="System" />
59 <Reference Include="System.Core">
60 <RequiredTargetFramework>3.5</RequiredTargetFramework>
61 </Reference>
62 </ItemGroup>
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" />
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 <DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
69 22 </ItemGroup>
70 <ItemGroup>
71 <ProjectReference Include="..\Implab\Implab.csproj">
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
23
24 </Project>
@@ -1,54 +1,59
1 using NUnit.Framework;
1 using Xunit;
2 2 using System;
3 using Implab.Formats.JSON;
4 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.Format.Test {
7 [TestFixture]
11 namespace Implab.Test {
8 12 public class JsonTests {
9 [Test]
13
14 [Fact]
10 15 public void TestScannerValidTokens() {
11 using (var scanner = new JSONScanner(@"9123, -123, 0, 0.1, -0.2, -0.1e3, 1.3E-3, ""some \t\n\u0020 text"", literal []{}:")) {
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 18 Tuple<JsonTokenType,object>[] expexted = {
14 new Tuple<JsonTokenType,object>(JsonTokenType.Number, 9123d),
15 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
16 new Tuple<JsonTokenType,object>(JsonTokenType.Number, -123d),
17 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
18 new Tuple<JsonTokenType,object>(JsonTokenType.Number, 0d),
19 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
20 new Tuple<JsonTokenType,object>(JsonTokenType.Number, 0.1d),
21 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
22 new Tuple<JsonTokenType,object>(JsonTokenType.Number, -0.2d),
23 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
24 new Tuple<JsonTokenType,object>(JsonTokenType.Number, -0.1e3d),
25 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
26 new Tuple<JsonTokenType,object>(JsonTokenType.Number, 1.3E-3d),
27 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
19 new Tuple<JsonTokenType,object>(JsonTokenType.Number, "9123"),
20 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null),
21 new Tuple<JsonTokenType,object>(JsonTokenType.Number, "-123"),
22 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null),
23 new Tuple<JsonTokenType,object>(JsonTokenType.Number, "0"),
24 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null),
25 new Tuple<JsonTokenType,object>(JsonTokenType.Number, "0.1"),
26 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null),
27 new Tuple<JsonTokenType,object>(JsonTokenType.Number, "-0.2"),
28 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null),
29 new Tuple<JsonTokenType,object>(JsonTokenType.Number, "-0.1e3"),
30 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null),
31 new Tuple<JsonTokenType,object>(JsonTokenType.Number, "1.3E-3"),
32 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null),
28 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 35 new Tuple<JsonTokenType,object>(JsonTokenType.Literal, "literal"),
31 new Tuple<JsonTokenType,object>(JsonTokenType.BeginArray, " ["),
32 new Tuple<JsonTokenType,object>(JsonTokenType.EndArray, "]"),
33 new Tuple<JsonTokenType,object>(JsonTokenType.BeginObject, "{"),
34 new Tuple<JsonTokenType,object>(JsonTokenType.EndObject, "}"),
35 new Tuple<JsonTokenType,object>(JsonTokenType.NameSeparator, ":")
36 new Tuple<JsonTokenType,object>(JsonTokenType.BeginArray, null),
37 new Tuple<JsonTokenType,object>(JsonTokenType.EndArray, null),
38 new Tuple<JsonTokenType,object>(JsonTokenType.BeginObject, null),
39 new Tuple<JsonTokenType,object>(JsonTokenType.EndObject, null),
40 new Tuple<JsonTokenType,object>(JsonTokenType.NameSeparator, null)
36 41 };
37 42
38 object value;
43 string value;
39 44 JsonTokenType tokenType;
40 45 for (var i = 0; i < expexted.Length; i++) {
41 46
42 Assert.IsTrue(scanner.ReadToken(out value, out tokenType));
43 Assert.AreEqual(expexted[i].Item1, tokenType);
44 Assert.AreEqual(expexted[i].Item2, value);
47 Assert.True(scanner.ReadToken(out value, out tokenType));
48 Assert.Equal(expexted[i].Item1, tokenType);
49 Assert.Equal(expexted[i].Item2, value);
45 50 }
46 51
47 Assert.IsFalse(scanner.ReadToken(out value, out tokenType));
52 Assert.False(scanner.ReadToken(out value, out tokenType));
48 53 }
49 54 }
50 55
51 [Test]
56 [Fact]
52 57 public void TestScannerBadTokens() {
53 58 var bad = new [] {
54 59 " 1",
@@ -66,22 +71,120 namespace Implab.Format.Test {
66 71 "-.123"
67 72 };
68 73
69 foreach (var json in bad)
70 using (var scanner = new JSONScanner(json)) {
74 foreach (var json in bad) {
75 using (var scanner = JsonStringScanner.Create(json)) {
71 76 try {
72 object value;
77 string value;
73 78 JsonTokenType token;
74 79 scanner.ReadToken(out value, out token);
75 80 if (!Object.Equals(value,json)) {
76 81 Console.WriteLine("'{0}' is read as {1}", json, value is String ? String.Format("'{0}'", value) : value );
77 82 continue;
78 83 }
79 Assert.Fail("Token '{0}' shouldn't pass", json);
84 Assert.True(false, $"Token '{json}' shouldn't pass");
80 85 } catch (ParserException e) {
81 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 }
@@ -1,13 +1,39
1 using Implab.Parallels;
1 using Implab;
2 using System;
2 3 using System.Threading;
3 4
4 5 namespace Implab.Test {
5 6 static class PromiseHelper {
6 public static IPromise<T> Sleep<T>(int timeout, T retVal) {
7 return AsyncPool.Invoke((ct) => {
8 ct.CancellationRequested(ct.CancelOperation);
9 Thread.Sleep(timeout);
10 return retVal;
7 public static IPromise<T> Sleep<T>(int timeout, T retVal, CancellationToken ct = default(CancellationToken)) {
8
9 Timer timer = null;
10
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 }
@@ -1,270 +1,69
1 
2 Microsoft Visual Studio Solution File, Format Version 11.00
3 # Visual Studio 2010
4 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Implab", "Implab\Implab.csproj", "{F550F1F8-8746-4AD0-9614-855F4C4B7F05}"
1
2 Microsoft Visual Studio Solution File, Format Version 12.00
3 # Visual Studio 15
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 7 EndProject
6 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{CE8D8D18-437A-445C-B662-4C2CE79A76F6}"
7 ProjectSection(SolutionItems) = preProject
8 Implab.vsmdi = Implab.vsmdi
9 Local.testsettings = Local.testsettings
10 TraceAndTestImpact.testsettings = TraceAndTestImpact.testsettings
11 EndProjectSection
8 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Implab.Test", "Implab.Test\Implab.Test.csproj", "{6CD0DA18-8D9B-4AA8-A3DC-17322E27335E}"
9 EndProject
10 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Implab.Playground", "Implab.Playground\Implab.Playground.csproj", "{100DFEB0-75BE-436F-ADDF-1F46EF433F46}"
12 11 EndProject
13 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Implab.Test", "Implab.Test\Implab.Test.csproj", "{63F92C0C-61BF-48C0-A377-8D67C3C661D0}"
12 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Implab.ServiceHost", "Implab.ServiceHost\Implab.ServiceHost.csproj", "{8B79FCBE-50DD-40A0-9B5E-E572072E4868}"
14 13 EndProject
15 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Implab.Fx", "Implab.Fx\Implab.Fx.csproj", "{06E706F8-6881-43EB-927E-FFC503AF6ABC}"
16 EndProject
17 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Implab.Fx.Test", "Implab.Fx.Test\Implab.Fx.Test.csproj", "{2F31E405-E267-4195-A05D-574093C21209}"
14 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Implab.ServiceHost.Test", "Implab.ServiceHost.Test\Implab.ServiceHost.Test.csproj", "{CB844F94-E555-4F25-A932-7CB85C98CF86}"
18 15 EndProject
19 16 Global
20 17 GlobalSection(SolutionConfigurationPlatforms) = preSolution
21 18 Debug|Any CPU = Debug|Any CPU
22 19 Release|Any CPU = Release|Any CPU
23 Debug 4.5|Any CPU = Debug 4.5|Any CPU
24 Release 4.5|Any CPU = Release 4.5|Any CPU
20 Debug|x64 = Debug|x64
21 Debug|x86 = Debug|x86
22 Release|x64 = Release|x64
23 Release|x86 = Release|x86
25 24 EndGlobalSection
26 25 GlobalSection(ProjectConfigurationPlatforms) = postSolution
27 {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Debug 4.5|Any CPU.ActiveCfg = Debug 4.5|Any CPU
28 {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Debug 4.5|Any CPU.Build.0 = Debug 4.5|Any CPU
29 {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
30 {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Debug|Any CPU.Build.0 = Debug|Any CPU
31 {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Release 4.5|Any CPU.ActiveCfg = Release 4.5|Any CPU
32 {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Release 4.5|Any CPU.Build.0 = Release 4.5|Any CPU
33 {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Release|Any CPU.ActiveCfg = Release|Any CPU
34 {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Release|Any CPU.Build.0 = Release|Any CPU
35 {2F31E405-E267-4195-A05D-574093C21209}.Debug 4.5|Any CPU.ActiveCfg = Debug 4.5|Any CPU
36 {2F31E405-E267-4195-A05D-574093C21209}.Debug 4.5|Any CPU.Build.0 = Debug 4.5|Any CPU
37 {2F31E405-E267-4195-A05D-574093C21209}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
38 {2F31E405-E267-4195-A05D-574093C21209}.Debug|Any CPU.Build.0 = Debug|Any CPU
39 {2F31E405-E267-4195-A05D-574093C21209}.Release 4.5|Any CPU.ActiveCfg = Release 4.5|Any CPU
40 {2F31E405-E267-4195-A05D-574093C21209}.Release 4.5|Any CPU.Build.0 = Release 4.5|Any CPU
41 {2F31E405-E267-4195-A05D-574093C21209}.Release|Any CPU.ActiveCfg = Release|Any CPU
42 {2F31E405-E267-4195-A05D-574093C21209}.Release|Any CPU.Build.0 = Release|Any CPU
43 {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Debug 4.5|Any CPU.ActiveCfg = Debug 4.5|Any CPU
44 {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Debug 4.5|Any CPU.Build.0 = Debug 4.5|Any CPU
45 {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
46 {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
47 {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Release 4.5|Any CPU.ActiveCfg = Release 4.5|Any CPU
48 {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Release 4.5|Any CPU.Build.0 = Release 4.5|Any CPU
49 {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
50 {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Release|Any CPU.Build.0 = Release|Any CPU
51 {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Debug 4.5|Any CPU.ActiveCfg = Debug 4.5|Any CPU
52 {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Debug 4.5|Any CPU.Build.0 = Debug 4.5|Any CPU
53 {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
54 {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Debug|Any CPU.Build.0 = Debug|Any CPU
55 {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Release 4.5|Any CPU.ActiveCfg = Release 4.5|Any CPU
56 {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Release 4.5|Any CPU.Build.0 = Release 4.5|Any CPU
57 {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Release|Any CPU.ActiveCfg = Release|Any CPU
58 {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Release|Any CPU.Build.0 = Release|Any CPU
59 EndGlobalSection
60 GlobalSection(NestedProjects) = preSolution
61 EndGlobalSection
62 GlobalSection(MonoDevelopProperties) = preSolution
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
26 {FF2052B6-9C8F-4022-A347-F07ABF635885}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 {FF2052B6-9C8F-4022-A347-F07ABF635885}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 {FF2052B6-9C8F-4022-A347-F07ABF635885}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 {FF2052B6-9C8F-4022-A347-F07ABF635885}.Release|Any CPU.Build.0 = Release|Any CPU
30 {6CD0DA18-8D9B-4AA8-A3DC-17322E27335E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
31 {6CD0DA18-8D9B-4AA8-A3DC-17322E27335E}.Debug|Any CPU.Build.0 = Debug|Any CPU
32 {6CD0DA18-8D9B-4AA8-A3DC-17322E27335E}.Release|Any CPU.ActiveCfg = Release|Any CPU
33 {6CD0DA18-8D9B-4AA8-A3DC-17322E27335E}.Release|Any CPU.Build.0 = Release|Any CPU
34 {100DFEB0-75BE-436F-ADDF-1F46EF433F46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
35 {100DFEB0-75BE-436F-ADDF-1F46EF433F46}.Debug|Any CPU.Build.0 = Debug|Any CPU
36 {100DFEB0-75BE-436F-ADDF-1F46EF433F46}.Release|Any CPU.ActiveCfg = Release|Any CPU
37 {100DFEB0-75BE-436F-ADDF-1F46EF433F46}.Release|Any CPU.Build.0 = Release|Any CPU
38 {8B79FCBE-50DD-40A0-9B5E-E572072E4868}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
39 {8B79FCBE-50DD-40A0-9B5E-E572072E4868}.Debug|Any CPU.Build.0 = Debug|Any CPU
40 {8B79FCBE-50DD-40A0-9B5E-E572072E4868}.Debug|x64.ActiveCfg = Debug|x64
41 {8B79FCBE-50DD-40A0-9B5E-E572072E4868}.Debug|x64.Build.0 = Debug|x64
42 {8B79FCBE-50DD-40A0-9B5E-E572072E4868}.Debug|x86.ActiveCfg = Debug|x86
43 {8B79FCBE-50DD-40A0-9B5E-E572072E4868}.Debug|x86.Build.0 = Debug|x86
44 {8B79FCBE-50DD-40A0-9B5E-E572072E4868}.Release|Any CPU.ActiveCfg = Release|Any CPU
45 {8B79FCBE-50DD-40A0-9B5E-E572072E4868}.Release|Any CPU.Build.0 = Release|Any CPU
46 {8B79FCBE-50DD-40A0-9B5E-E572072E4868}.Release|x64.ActiveCfg = Release|x64
47 {8B79FCBE-50DD-40A0-9B5E-E572072E4868}.Release|x64.Build.0 = Release|x64
48 {8B79FCBE-50DD-40A0-9B5E-E572072E4868}.Release|x86.ActiveCfg = Release|x86
49 {8B79FCBE-50DD-40A0-9B5E-E572072E4868}.Release|x86.Build.0 = Release|x86
50 {CB844F94-E555-4F25-A932-7CB85C98CF86}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
51 {CB844F94-E555-4F25-A932-7CB85C98CF86}.Debug|Any CPU.Build.0 = Debug|Any CPU
52 {CB844F94-E555-4F25-A932-7CB85C98CF86}.Debug|x64.ActiveCfg = Debug|x64
53 {CB844F94-E555-4F25-A932-7CB85C98CF86}.Debug|x64.Build.0 = Debug|x64
54 {CB844F94-E555-4F25-A932-7CB85C98CF86}.Debug|x86.ActiveCfg = Debug|x86
55 {CB844F94-E555-4F25-A932-7CB85C98CF86}.Debug|x86.Build.0 = Debug|x86
56 {CB844F94-E555-4F25-A932-7CB85C98CF86}.Release|Any CPU.ActiveCfg = Release|Any CPU
57 {CB844F94-E555-4F25-A932-7CB85C98CF86}.Release|Any CPU.Build.0 = Release|Any CPU
58 {CB844F94-E555-4F25-A932-7CB85C98CF86}.Release|x64.ActiveCfg = Release|x64
59 {CB844F94-E555-4F25-A932-7CB85C98CF86}.Release|x64.Build.0 = Release|x64
60 {CB844F94-E555-4F25-A932-7CB85C98CF86}.Release|x86.ActiveCfg = Release|x86
61 {CB844F94-E555-4F25-A932-7CB85C98CF86}.Release|x86.Build.0 = Release|x86
266 62 EndGlobalSection
267 63 GlobalSection(SolutionProperties) = preSolution
268 64 HideSolutionNode = FALSE
269 65 EndGlobalSection
66 GlobalSection(ExtensibilityGlobals) = postSolution
67 SolutionGuid = {36D837FC-4CDD-4AEA-87BF-F130FEB22E02}
68 EndGlobalSection
270 69 EndGlobal
@@ -1,277 +1,26
1 <?xml version="1.0" encoding="utf-8"?>
2 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
1 <Project Sdk="Microsoft.NET.Sdk">
2
3 3 <PropertyGroup>
4 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
5 <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
6 <ProjectGuid>{F550F1F8-8746-4AD0-9614-855F4C4B7F05}</ProjectGuid>
7 <OutputType>Library</OutputType>
8 <RootNamespace>Implab</RootNamespace>
9 <AssemblyName>Implab</AssemblyName>
10 <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
11 <ProductVersion>8.0.30703</ProductVersion>
12 <SchemaVersion>2.0</SchemaVersion>
13 </PropertyGroup>
14 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
15 <DebugSymbols>true</DebugSymbols>
16 <DebugType>full</DebugType>
17 <Optimize>false</Optimize>
18 <OutputPath>bin\Debug</OutputPath>
19 <DefineConstants>TRACE;DEBUG;</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>
4 <Authors>Sergey Smirnov</Authors>
5 <Title>Implab library</Title>
6 <Description>Provides some helper clesses like XML serialization helpers, JSON XML reader,
7 JSON pull-parser, ECMA-style promises, lightweight synchonization routines Signal
8 and SharedLock, Trace helpers on top of System.Diagnostics, ObjectPool etc.
9 </Description>
10 <Copyright>2012-2018 Sergey Smirnov</Copyright>
11 <Version>3.0.14</Version>
12 <PackageLicenseUrl>https://bitbucket.org/wozard/implabnet/src/v3/Implab/license.txt</PackageLicenseUrl>
13 <PackageProjectUrl>https://bitbucket.org/wozard/implabnet</PackageProjectUrl>
14 <RepositoryUrl>https://bitbucket.org/wozard/implabnet</RepositoryUrl>
15 <RepositoryType>mercurial</RepositoryType>
16 <PackageTags>IMPLAB;Json pull-parser;Json Xml;async;diagnostics;serialization;</PackageTags>
17 <TargetFrameworks>netstandard2.0;net46</TargetFrameworks>
18 <FrameworkPathOverride Condition="'$(TargetFramework)'=='net46' and '$(OSTYPE)'=='linux'">/usr/lib/mono/4.5/</FrameworkPathOverride>
19 <DefineConstants Condition="'$(TargetFramework)'=='net46'">NETFX_TRACE_BUG;$(DefineConstants)</DefineConstants>
32 20 </PropertyGroup>
33 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug 4.5|AnyCPU' ">
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>
21
76 22 <ItemGroup>
77 <Compile Include="CustomEqualityComparer.cs" />
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" />
23 <EmbeddedResource Include="src\Xml\json.xsl"/>
197 24 </ItemGroup>
198 <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
199 <ItemGroup />
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="&#xA;" IndentContent="True" ContentIndentString="&#x9;" AttributesInNewLine="False" MaxAttributesPerLine="10" AttributesIndentString="&#x9;" WrapAttributes="False" AlignAttributes="False" AlignAttributeValues="False" QuoteChar="&quot;" 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
25
26 </Project>
@@ -2,296 +2,126
2 2 using Implab.Parallels;
3 3 using System.Threading;
4 4 using System.Reflection;
5 using System.Diagnostics;
5 6
6 7 namespace Implab {
7 public abstract class AbstractEvent<THandler> : ICancellationToken, ICancellable {
8
9 const int UNRESOLVED_SATE = 0;
10 const int TRANSITIONAL_STATE = 1;
11 protected const int SUCCEEDED_STATE = 2;
12 protected const int REJECTED_STATE = 3;
13 protected const int CANCELLED_STATE = 4;
14
15 const int CANCEL_NOT_REQUESTED = 0;
16 const int CANCEL_REQUESTING = 1;
17 const int CANCEL_REQUESTED = 2;
18
19 const int RESERVED_HANDLERS_COUNT = 4;
20
21 int m_state;
22 Exception m_error;
23 int m_handlersCount;
8 /// <summary>
9 /// Abstract class for creation of custom one-shot thread safe events.
10 /// </summary>
11 /// <remarks>
12 /// <para>
13 /// An event is something that should happen in the future and the
14 /// triggering of the event causes execution of some pending actions
15 /// which are formely event handlers. One-shot events occur only once
16 /// and any handler added after the event is triggered should run
17 /// without a delay.
18 /// </para>
19 /// <para>
20 /// The lifecycle of the one-shot event is tipically consists of following
21 /// phases.
22 /// <list>
23 /// <description>Pending state. This is the initial state of the event. Any
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];
26 THandler[] m_handlers;
27 MTQueue<THandler> m_extraHandlers;
28 int m_handlerPointer = -1;
29 int m_handlersCommited;
40 const int TransitionalState = 1;
30 41
31 int m_cancelRequest;
32 Exception m_cancelationReason;
33 MTQueue<Action<Exception>> m_cancelationHandlers;
42 const int ResolvedState = 2;
34 43
44 volatile int m_state;
35 45
36 #region state managment
37 bool BeginTransit() {
38 return UNRESOLVED_SATE == Interlocked.CompareExchange(ref m_state, TRANSITIONAL_STATE, UNRESOLVED_SATE);
39 }
46 THandler m_handler;
47 SimpleAsyncQueue<THandler> m_extraHandlers;
40 48
41 void CompleteTransit(int state) {
42 if (TRANSITIONAL_STATE != Interlocked.CompareExchange(ref m_state, state, TRANSITIONAL_STATE))
43 throw new InvalidOperationException("Can't complete transition when the object isn't in the transitional state");
44 }
45
46 void WaitTransition() {
47 while (m_state == TRANSITIONAL_STATE) {
48 Thread.MemoryBarrier();
49 public bool IsResolved {
50 get {
51 return m_state > TransitionalState;
49 52 }
50 53 }
51 54
52 protected bool BeginSetResult() {
53 if (!BeginTransit()) {
54 WaitTransition();
55 if (m_state != CANCELLED_STATE)
56 throw new InvalidOperationException("The promise is already resolved");
57 return false;
58 }
59 return true;
55 #region state managment
56 protected bool BeginTransit() {
57 return PendingState == Interlocked.CompareExchange(ref m_state, TransitionalState, PendingState);
60 58 }
61 59
62 protected void EndSetResult() {
63 CompleteTransit(SUCCEEDED_STATE);
60 protected void CompleteTransit() {
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 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
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);
80 protected abstract void SignalHandler(THandler handler);
105 81
106 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 while (m_extraHandlers.TryDequeue(out handler))
121 SignalHandler(handler, m_state);
122 }
84 while (TryDequeueHandler(out handler))
85 SignalHandler(handler);
123 86 }
124 87
125 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 90 #region handlers managment
148 91
149 92 protected void AddHandler(THandler handler) {
150 93
151 if (m_state > 1) {
94 if (IsResolved) {
152 95 // the promise is in the resolved state, just invoke the handler
153 SignalHandler(handler, m_state);
96 SignalHandler(handler);
154 97 } else {
155 var slot = Interlocked.Increment(ref m_handlersCount) - 1;
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 }
98 EnqueueHandler(handler);
170 99
171 if (m_state > 1) {
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))
100 if (IsResolved && TryDequeueHandler(out handler))
194 101 // if the promise have been resolved while we was adding the handler to the queue
195 102 // we can't guarantee that someone is still processing it
196 103 // therefore we need to fetch a handler from the queue and execute it
197 104 // note that fetched handler may be not the one that we have added
198 105 // even we can fetch no handlers at all :)
199 SignalHandler(handler, m_state);
106 SignalHandler(handler);
200 107 }
201 }
108
202 109 }
203 110
204 #endregion
205
206 #region IPromise implementation
207
208 public bool IsResolved {
209 get {
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;
111 void EnqueueHandler(THandler handler) {
112 if (Interlocked.CompareExchange(ref m_handler, handler, null) != null) {
113 if (m_extraHandlers == null)
114 // compare-exchange will protect from loosing already created queue
115 Interlocked.CompareExchange(ref m_extraHandlers, new SimpleAsyncQueue<THandler>(), null);
116 m_extraHandlers.Enqueue(handler);
227 117 }
228 118 }
229 119
230 public bool CancelOperationIfRequested() {
231 if (IsCancellationRequested) {
232 CancelOperation(CancellationReason);
120 bool TryDequeueHandler(out THandler handler) {
121 handler = Interlocked.Exchange(ref m_handler, null);
122 if (handler != null)
233 123 return true;
234 }
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 }
124 return m_extraHandlers != null && m_extraHandlers.TryDequeue(out handler);
295 125 }
296 126
297 127 #endregion
@@ -1,9 +1,9
1 1
2 2 namespace Implab.Automaton {
3 3 public static class AutomatonConst {
4 public const int UNREACHABLE_STATE = -1;
4 public const int UnreachableState = -1;
5 5
6 public const int UNCLASSIFIED_INPUT = 0;
6 public const int UnclassifiedInput = 0;
7 7 }
8 8 }
9 9
@@ -1,7 +1,7
1 1 using System;
2 2
3 3 namespace Implab.Automaton {
4 public struct AutomatonTransition : IEquatable<AutomatonTransition> {
4 public class AutomatonTransition : IEquatable<AutomatonTransition> {
5 5 public readonly int s1;
6 6 public readonly int s2;
7 7 public readonly int edge;
@@ -28,6 +28,14 namespace Implab.Automaton {
28 28 public override int GetHashCode() {
29 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
@@ -20,7 +20,7 namespace Implab.Automaton {
20 20 #region IDFADefinition implementation
21 21
22 22 public bool IsFinalState(int s) {
23 Safe.ArgumentInRange(s, 0, m_stateCount, "s");
23 Safe.ArgumentInRange(s >= 0 && s < m_stateCount, nameof(s));
24 24
25 25 return m_finalStates.Contains(s);
26 26 }
@@ -46,7 +46,7 namespace Implab.Automaton {
46 46 #endregion
47 47
48 48 public void SetInitialState(int s) {
49 Safe.ArgumentAssert(s >= 0, "s");
49 Safe.ArgumentInRange(s >= 0, nameof(s));
50 50 m_stateCount = Math.Max(m_stateCount, s + 1);
51 51 m_initialState = s;
52 52 }
@@ -57,9 +57,9 namespace Implab.Automaton {
57 57 }
58 58
59 59 public void Add(AutomatonTransition item) {
60 Safe.ArgumentAssert(item.s1 >= 0, "item");
61 Safe.ArgumentAssert(item.s2 >= 0, "item");
62 Safe.ArgumentAssert(item.edge >= 0, "item");
60 Safe.ArgumentAssert(item.s1 >= 0, nameof(item));
61 Safe.ArgumentAssert(item.s2 >= 0, nameof(item));
62 Safe.ArgumentAssert(item.edge >= 0, nameof(item));
63 63
64 64 m_stateCount = Math.Max(m_stateCount, Math.Max(item.s1, item.s2) + 1);
65 65 m_symbolCount = Math.Max(m_symbolCount, item.edge + 1);
@@ -116,10 +116,10 namespace Implab.Automaton {
116 116
117 117 for (int i = 0; i < StateCount; i++)
118 118 for (int j = 0; j < AlphabetSize; j++)
119 table[i, j] = AutomatonConst.UNREACHABLE_STATE;
119 table[i, j] = AutomatonConst.UnreachableState;
120 120
121 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 124 return table;
125 125 }
@@ -290,11 +290,11 namespace Implab.Automaton {
290 290
291 291 var nextCls = 0;
292 292 foreach (var item in minClasses) {
293 if (nextCls == AutomatonConst.UNCLASSIFIED_INPUT)
293 if (nextCls == AutomatonConst.UnclassifiedInput)
294 294 nextCls++;
295 295
296 296 // сохраняем DFAConst.UNCLASSIFIED_INPUT
297 var cls = item.Contains(AutomatonConst.UNCLASSIFIED_INPUT) ? AutomatonConst.UNCLASSIFIED_INPUT : nextCls++;
297 var cls = item.Contains(AutomatonConst.UnclassifiedInput) ? AutomatonConst.UnclassifiedInput : nextCls++;
298 298 optimalDFA.AddSymbol(cls);
299 299
300 300 foreach (var a in item)
@@ -311,7 +311,7 namespace Implab.Automaton {
311 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 315 Safe.ArgumentNotNull(inputAlphabet, "inputAlphabet");
316 316 Safe.ArgumentNotNull(stateAlphabet, "stateAlphabet");
317 317
@@ -326,7 +326,7 namespace Implab.Automaton {
326 326 data.Add(String.Format(
327 327 "{0} -> {2} [label={1}];",
328 328 String.Join("", stateAlphabet.GetSymbols(t.s1)),
329 ToLiteral(ToLiteral(String.Join("", t.edge == AutomatonConst.UNCLASSIFIED_INPUT ? new [] { "@" } : inputAlphabet.GetSymbols(t.edge).Select(x => x.ToString())))),
329 ToLiteral(ToLiteral(String.Join("", t.edge == AutomatonConst.UnclassifiedInput ? new [] { "@" } : inputAlphabet.GetSymbols(t.edge).Select(x => x.ToString())))),
330 330 String.Join("", stateAlphabet.GetSymbols(t.s2))
331 331 ));
332 332 data.Add("}");
@@ -343,6 +343,6 namespace Implab.Automaton {
343 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
1 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
1 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
@@ -54,7 +54,7 namespace Implab.Automaton {
54 54 return cls;
55 55 if (!m_supportUnclassified)
56 56 throw new ArgumentOutOfRangeException("symbol", "The specified symbol isn't in the alphabet");
57 return AutomatonConst.UNCLASSIFIED_INPUT;
57 return AutomatonConst.UnclassifiedInput;
58 58 }
59 59
60 60 public int Count {
1 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
1 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
1 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
1 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
1 NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/IVisitor.cs to Implab/src/Automaton/RegularExpressions/IVisitor.cs
@@ -77,14 +77,14 namespace Implab.Automaton.RegularExpres
77 77 return states.GroupBy(x => m_tags[x] ?? new TTag[0], arrayComparer).Select(g => new HashSet<int>(g));
78 78 }
79 79
80 public override string ToString() {
80 /*public override string ToString() {
81 81 var states = new MapAlphabet<string>(false, null);
82 82
83 83 for (int i = 0; i < StateCount; i++)
84 84 states.DefineSymbol(string.Format("s{0}", i), i);
85 85
86 86 return string.Format("//[RegularDFA {1} x {2}]\n{0}", PrintDFA(InputAlphabet, states),StateCount, AlphabetSize);
87 }
87 }*/
88 88
89 89 }
90 90 }
@@ -129,7 +129,7 namespace Implab.Automaton.RegularExpres
129 129 if (m_root == null)
130 130 m_root = token;
131 131 m_idx++;
132 m_indexes[m_idx] = AutomatonConst.UNCLASSIFIED_INPUT;
132 m_indexes[m_idx] = AutomatonConst.UnclassifiedInput;
133 133 m_firstpos = new HashSet<int>(new[] { m_idx });
134 134 m_lastpos = new HashSet<int>(new[] { m_idx });
135 135 Followpos(m_idx);
1 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
1 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
@@ -1,5 +1,6
1 1 using Implab.Diagnostics;
2 2 using System;
3 using System.Diagnostics.CodeAnalysis;
3 4 using System.Threading;
4 5
5 6 namespace Implab.Components {
@@ -8,15 +9,10 namespace Implab.Components {
8 9 /// </summary>
9 10 public class Disposable : IDisposable {
10 11
11 int m_disposed;
12
13 12 public event EventHandler Disposed;
14 13
15 14 public bool IsDisposed {
16 get {
17 Thread.MemoryBarrier();
18 return m_disposed != 0;
19 }
15 get; private set;
20 16 }
21 17
22 18 /// <summary>
@@ -24,43 +20,8 namespace Implab.Components {
24 20 /// </summary>
25 21 /// <exception cref="ObjectDisposedException">The object is disposed</exception>
26 22 /// <remarks>
27 /// Успешная проверка того, что объект не освобожден еще не гарантирует, что он не
28 /// будет освобожден сразу после нее, поэтому методы использующие проверку должны
29 /// учитывать, что объект может быть освобожден из параллельного потока.
30 /// Данны метод служит для упрощения отладки ошибок при использовании объекта после его
31 /// освобождения.
32 /// </remarks>
33 /// <example>
34 /// // пример синхронизированного освобождения ресурсов
35 /// class FileStore : Disposable {
36 /// readonly TextWriter m_file;
37 /// readonly obejct m_sync = new object();
38 ///
39 /// public FileStore(string file) {
40 /// m_file = new TextWriter(File.OpenWrite(file));
41 /// }
42 ///
43 /// public void Write(string text) {
44 /// lock(m_sync) {
45 /// AssertNotDisposed();
46 /// m_file.Write(text);
47 /// }
48 /// }
49 ///
50 /// protected override void Dispose(bool disposing) {
51 /// if (disposing)
52 /// lock(m_sync) {
53 /// m_file.Dipose();
54 /// base.Dispose(true);
55 /// }
56 /// else
57 /// base.Dispose(false);
58 /// }
59 /// }
60 /// <example>
61 23 protected void AssertNotDisposed() {
62 Thread.MemoryBarrier();
63 if (m_disposed != 0)
24 if (IsDisposed)
64 25 throw new ObjectDisposedException(ToString());
65 26 }
66 27 /// <summary>
@@ -74,30 +35,21 namespace Implab.Components {
74 35 /// из нескольких потоков.
75 36 /// </remarks>
76 37 protected virtual void Dispose(bool disposing) {
77 if (disposing) {
78 EventHandler temp = Disposed;
79 if (temp != null)
80 temp(this, EventArgs.Empty);
81 }
38 if (disposing)
39 Disposed.DispatchEvent(this, EventArgs.Empty);
82 40 }
83 41
42 [SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly", Justification = "Dipose(bool) and GC.SuppessFinalize are called")]
84 43 public void Dispose() {
85 if (Interlocked.Increment(ref m_disposed) == 1) {
44 if(!IsDisposed) {
45 IsDisposed = true;
86 46 Dispose(true);
87 47 GC.SuppressFinalize(this);
88 48 }
89 49 }
90 50
91 /// <summary>
92 /// Записывает сообщение об утечке объекта.
93 /// </summary>
94 protected virtual void ReportObjectLeaks() {
95 TraceLog.TraceWarning("The object is marked as disposable but isn't disposed properly: {0}", this);
96 }
97
98 51 ~Disposable() {
99 52 Dispose(false);
100 ReportObjectLeaks();
101 53 }
102 54 }
103 55 } No newline at end of file
@@ -6,10 +6,10 using System.Diagnostics.CodeAnalysis;
6 6
7 7 namespace Implab.Components {
8 8 /// <summary>
9 /// The base class for implementing pools of disposable objects.
9 /// The base class for implementing thread-safe pools of disposable objects.
10 10 /// </summary>
11 11 /// <remarks>
12 /// <para>This class maintains a set of pre-created objects and which are frequently allocated and released
12 /// <para>This class maintains a set of pre-created objects which are frequently allocated and released
13 13 /// by clients. The pool maintains maximum number of unsued object, any object above this limit is disposed,
14 14 /// if the pool is empty it will create new objects on demand.</para>
15 15 /// <para>Instances of this class are thread-safe.</para>
@@ -15,6 +15,8
15 15
16 16 Stopping,
17 17
18 Stopped,
19
18 20 Failed,
19 21
20 22 Disposed,
1 NO CONTENT: file renamed from Implab/Components/IFactory.cs to Implab/src/Components/IFactory.cs
@@ -1,21 +1,30
1 1 using System;
2 using System.Threading;
2 3
3 4 namespace Implab.Components {
4 5 /// <summary>
5 6 /// Initializable components are created and initialized in two steps, first we have create the component,
6 /// then we have to complete it's creation by calling an <see cref="Init()"/> method. All parameters needed
7 /// to complete the initialization must be passed before the calling <see cref="Init()"/>
7 /// then we have to complete it's creation by calling an <see cref="Initialize()"/> method. All parameters needed
8 /// to complete the initialization must be passed before the calling <see cref="Initialize()"/>
8 9 /// </summary>
9 10 public interface IInitializable {
10 11 /// <summary>
11 12 /// Completes initialization.
12 13 /// </summary>
13 14 /// <remarks>
15 /// <para>
14 16 /// Normally virtual methods shouldn't be called from the constructor, due to the incomplete object state, but
15 17 /// they can be called from this method. This method is also usefull when we constructing a complex grpah
16 18 /// of components where cyclic references may take place.
19 /// </para>
20 /// <para>
21 /// In asyncronous patterns <see cref="Initialize()"/> can be called
22 /// to start initialization and the <see cref="IRunnable.Completion"/>
23 /// property can be used to track operation completion.
24 /// </para>
17 25 /// </remarks>
18 void Init();
26 void Initialize();
27 void Initialize(CancellationToken ct);
19 28 }
20 29 }
21 30
@@ -1,13 +1,53
1 1 using System;
2 using System.Threading;
3 using System.Threading.Tasks;
2 4
3 5 namespace Implab.Components {
6 /// <summary>
7 /// Interface for the component which performs a long running task.
8 /// </summary>
9 /// <remarks>
10 /// The access to the runnable component should be sequential, the
11 /// componet should support asynchronous completion of the initiated
12 /// operation but operations itself must be initiated sequentially.
13 /// </remarks>
4 14 public interface IRunnable {
5 IPromise Start();
15 /// <summary>
16 /// Starts this instance
17 /// </summary>
18 /// <remarks>
19 /// This operation is cancellable and it's expected to move to
20 /// the failed state or just ignore the cancellation request,
21 /// </remarks>
22 void Start();
23 void Start(CancellationToken ct);
6 24
7 IPromise Stop();
25 /// <summary>
26 /// Stops this instance and releases all resources, after the
27 /// instance is stopped it is moved to Disposed state and
28 /// can't be reused.
29 /// </summary>
30 /// <remarks>
31 /// If the componet was in the starting state the pending operation
32 /// will be requested to cancel. The stop operatin will be
33 /// performed only if the component in the running state.
34 /// </remarks>
35 void Stop();
36 void Stop(CancellationToken ct);
8 37
38 /// <summary>
39 /// Current state of the componenet, dynamically reflects the current state.
40 /// </summary>
9 41 ExecutionState State { get; }
10 42
43 /// <summary>
44 /// Event to monitor the state of the component.
45 /// </summary>
46 event EventHandler<StateChangeEventArgs> StateChanged;
47
48 /// <summary>
49 /// The last error
50 /// </summary>
11 51 Exception LastError { get; }
12 52 }
13 53 }
@@ -8,6 +8,7 namespace Implab.Components {
8 8 /// <remarks>
9 9 /// Usefull when dealing with memory-intensive objects which are frequently used.
10 10 /// This class is similar to <see cref="ObjectPool{T}"/> except it is a singleton.
11 /// This class can't be used to hold diposable objects.
11 12 /// </remarks>
12 13 public class LazyAndWeak<T> where T : class {
13 14
@@ -26,7 +26,7 namespace Implab.Components {
26 26 }
27 27
28 28 protected ObjectPool(int size) {
29 Safe.ArgumentInRange(size,1,size,"size");
29 Safe.ArgumentInRange(size > 0, nameof(size));
30 30
31 31 m_size = size;
32 32 }
1 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
1 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
1 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
1 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
1 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
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 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
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed, binary diff hidden
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed, binary diff hidden
1 NO CONTENT: file was removed, binary diff hidden
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
1 NO CONTENT: file was removed, binary diff hidden
1 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
1 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
1 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
1 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
1 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
1 NO CONTENT: file was removed, binary diff hidden
1 NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
General Comments 3
Under Review
author

Auto status change to "Under Review"

Approved
author

ok, latest stable version should be in default

note
author

Pull request merged and closed