##// END OF EJS Templates
Implab: added XmlDefaultSeializer (SerializersPool is now obsolete)...
cin -
r278:6691aff01de1 v3
parent child
Show More
@@ -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,29
1 using System;
2
3 namespace Implab.ServiceHost.Unity {
4 public class FactoryActivator : FactoryAbstractRegistratrion {
5
6 public Type FactoryType { get; set; }
7
8 public string FactoryName { get; set; }
9
10 public new Type RegistrationType { get; set; }
11
12 public override void Visit(FactoryRegistrationBuilder builder) {
13 base.Visit(builder);
14
15 builder.GetType()
16 .GetMethod(
17 nameof(FactoryRegistrationBuilder.SetFactoryDependency)
18 , new[] { typeof(string) }
19 )
20 .MakeGenericMethod(FactoryType, RegistrationType)
21 .Invoke(builder, new[] { FactoryName });
22 }
23
24 public override Type GetRegistrationType(Func<string, Type> resolver) {
25 return RegistrationType;
26 }
27
28 }
29 } No newline at end of file
@@ -0,0 +1,72
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 {
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 };
41 activator.Visit(builder);
42 }
43 } else {
44 // если регистрация явно не задана, в качестве сервиса для регистрации
45 // используется тип создаваемый фабрикой, который будет добавлен в контейнер
46 // с темже именем, что и сама фабрика (разные типы могут иметь одно имя для регистрации)
47 var providedType = (
48 factoryType.IsGenericType && factoryType.GetGenericTypeDefinition() == typeof(IFactory<>) ?
49 factoryType :
50 factoryType.GetInterface(typeof(IFactory<>).FullName)
51 )?
52 .GetGenericArguments()[0];
53
54 // не удалось определеить тип
55 if (providedType == null)
56 throw new ArgumentException("Failed to determine a type provided by the factory");
57
58 if (providedType.IsGenericParameter)
59 throw new ArgumentException("Can't register a generic type paramter as a service");
60
61 var activator = new FactoryActivator {
62 Name = Name,
63 RegistrationType = providedType,
64 FactoryName = Name,
65 FactoryType = factoryType
66 };
67
68 activator.Visit(builder);
69 }
70 }
71 }
72 } No newline at end of file
@@ -0,0 +1,5
1 namespace Implab.ServiceHost.Unity {
2 public interface IFactoryMemberInjection {
3 void Visit(FactoryRegistrationBuilder builder);
4 }
5 } No newline at end of file
@@ -0,0 +1,7
1 using System.Collections.Generic;
2
3 namespace Implab.ServiceHost.Unity {
4 public interface IFactoryRegistration : IRegistration {
5 IEnumerable<IFactoryMemberInjection> MemberInjections { get; }
6 }
7 } 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,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,11
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 } 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,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,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,14
1 using System.Xml.Serialization;
2 using Implab.Components;
3
4 namespace Implab.Xml {
5 /// <summary>
6 /// This class used to get default serializer for the specified type <typeparamref name="T"/>.
7 /// </summary>
8 /// <typeparam name="T">The type used to create <see cref="XmlSerializer"/></typeparam>
9 public static class XmlDefaultSerializer<T> {
10 static readonly LazyAndWeak<XmlSerializer> m_instance = new LazyAndWeak<XmlSerializer>(() => new XmlSerializer(typeof(T)));
11
12 public static XmlSerializer Instance { get { return m_instance.Value; } }
13 }
14 } No newline at end of file
@@ -0,0 +1,89
1 using System.IO;
2 using System.Text;
3 using System.Xml;
4 using System.Xml.Linq;
5 using System.Xml.Serialization;
6
7 namespace Implab.Xml {
8 public static class XmlSerializerExtensions {
9
10 public static void Serialize(this XmlSerializer that, object obj, XmlElement element) {
11 Safe.ArgumentNotNull(that, nameof(that));
12 using (var writer = element.CreateNavigator().AppendChild())
13 that.Serialize(writer, obj);
14 }
15
16 public static void Serialize(this XmlSerializer that, object obj, XElement element) {
17 Safe.ArgumentNotNull(that, nameof(that));
18 using (var writer = element.CreateWriter())
19 that.Serialize(writer, obj);
20 }
21
22 public static XDocument SerializeAsXDocumnet(this XmlSerializer that, object obj) {
23 Safe.ArgumentNotNull(that, nameof(that));
24 var doc = new XDocument();
25 using (var writer = doc.CreateWriter()) {
26 that.Serialize(writer, obj);
27 }
28 return doc;
29 }
30
31 public static XmlDocument SerializeAsXmlDocument(this XmlSerializer that, object obj) {
32 Safe.ArgumentNotNull(that, nameof(that));
33 var doc = new XmlDocument();
34 using (var writer = doc.CreateNavigator().AppendChild()) {
35 that.Serialize(writer, obj);
36 }
37 return doc;
38 }
39 public static string SerializeAsString(this XmlSerializer that, object obj) {
40 Safe.ArgumentNotNull(that, nameof(that));
41 using (var writer = new StringWriter()) {
42 that.Serialize(writer, obj);
43 return writer.ToString();
44 }
45 }
46
47 public static void SerializeToFile(this XmlSerializer that, object obj, string file, Encoding encoding) {
48 Safe.ArgumentNotNull(that, nameof(that));
49 using (var writer = new StreamWriter(File.Create(file),encoding))
50 that.Serialize(writer, obj);
51 }
52
53 public static void SerializeToFile(this XmlSerializer that, object obj, string file) {
54 SerializeToFile(that, obj, file, Encoding.UTF8);
55 }
56
57 public static object Deserialize(this XmlSerializer that, XmlElement element) {
58 Safe.ArgumentNotNull(that, nameof(that));
59 Safe.ArgumentNotNull(element, nameof(element));
60
61 using (var reader = element.CreateNavigator().ReadSubtree())
62 return that.Deserialize(reader);
63 }
64
65 public static object Deserialize(this XmlSerializer that, XElement element) {
66 Safe.ArgumentNotNull(that, nameof(that));
67 Safe.ArgumentNotNull(element, nameof(element));
68
69 using (var reader = element.CreateReader())
70 return that.Deserialize(reader);
71 }
72
73 public static object DeserializeFromString(this XmlSerializer that, string text) {
74 Safe.ArgumentNotNull(that, nameof(that));
75
76 using(var reader = new StringReader(text))
77 return that.Deserialize(reader);
78 }
79
80 public static object DeserializeFromFile(this XmlSerializer that, string file) {
81 Safe.ArgumentNotNull(that, nameof(that));
82
83 using(var reader = File.OpenRead(file))
84 return that.Deserialize(reader);
85 }
86
87
88 }
89 } No newline at end of file
@@ -1,114 +1,136
1 1 using System;
2 2 using System.Collections.Generic;
3 3 using System.Diagnostics;
4 4 using System.Linq;
5 using Implab.Components;
5 6 using Implab.Diagnostics;
6 7 using Implab.ServiceHost.Unity;
7 8 using Implab.Xml;
8 9 using Unity;
9 10 using Unity.Injection;
10 11 using Unity.Registration;
11 12
12 13 namespace Implab.Playground {
13 14
14 15 public class Foo {
15 16
16 17 public class Bar {
17 18
18 19 }
19 20
20 21 public string Name { get; set; }
21 22
22 23 public int IntValue { get; set; }
23 24
24 25 public string StringValue { get; set; }
25 26
26 27 public void AddRange(Foo[] items) {
27 28 Console.WriteLine($"AddRange: Foo[]");
28 29 }
29 30
30 31 }
31 32
33 public class FooFactory : IFactory<Foo>, IFactory<Foo.Bar> {
34
35 public bool UseSsl { get; set; }
36
37 public string Connection { get; set; }
38
39 public Foo Create() {
40 return new Foo() {
41 Name = "AutoFac"
42 };
43 }
44
45 Foo.Bar IFactory<Foo.Bar>.Create() {
46 return new Foo.Bar();
47 }
48 }
49
32 50 public interface IContainer<T> {
33 51 T Instance { get; set; }
34 52 }
35 53
36 54 public class Container<T> : IContainer<T> {
55 public class Bar {
56
57 }
58
59 public class Bar<T2> {
60 public class Baz {
61
62 }
63
64 }
65
37 66 public Container() {
38 67
39 68 }
40 69
41 70 public Container(T instance) {
42 71 Instance = instance;
43 72 }
44 73
45 74 public T Instance { get; set; }
46 75
47 76 public void SetInstance(T value) {
48 77 Instance = value;
49 78 }
50 79
51 80 public void AddRange(List<T> items) {
52 81 Console.WriteLine($"AddRange: {typeof(List<T>)}");
53 82 }
54 83
55 84 public void AddRange(T[] items) {
56 85 Console.WriteLine($"AddRange: T[] ofType {typeof(T[])}");
57 86 }
58 87 }
59 88
60 89 public class Program {
61 90
62 91 static void Main(string[] args) {
63 92 var listener = new SimpleTraceListener(Console.Out);
64 93 var source = Trace<TypeResolver>.TraceSource;
65 94 source.Switch.Level = SourceLevels.All;
66 95 source.Listeners.Add(listener);
67 96
68 var stopwatch = new Stopwatch();
69 stopwatch.Start();
70
71 var ctx = new ContainerBuilder();
72
73 Console.WriteLine($"Created: {stopwatch.ElapsedMilliseconds}");
74 stopwatch.Restart();
75
76 ctx.LoadConfig("data/sample.xml");
77
78 Console.WriteLine($"Loaded: {stopwatch.ElapsedMilliseconds}");
97 var resolver = new TypeResolver();
98 resolver.AddNamespace("System");
99 resolver.AddNamespace("System.Collections.Generic");
100 resolver.AddNamespace("Implab.Playground");
101 resolver.AddMapping("string", typeof(string));
102 resolver.AddMapping("listOf`1", typeof(List<>));
79 103
80 var container = ctx.Container;
104 var spec = TypeReference.Parse("Container{listOf{string}}+Bar{List{string}}");
81 105
82 stopwatch.Restart();
83 var instace1 = container.Resolve<IContainer<string>>();
84 Console.WriteLine($"Resolved1: {stopwatch.ElapsedMilliseconds}");
106 var t = resolver.Resolve(spec, true);
85 107
86 stopwatch.Restart();
87 var instace2 = container.Resolve<IContainer<Foo>>();
88 Console.WriteLine($"Resolved2: {stopwatch.ElapsedMilliseconds}");
89
90 DisplayContainerRegistrations(container);
108 Console.WriteLine("{0}", t);
109 Console.WriteLine("Spec: {0}", spec);
110 Console.WriteLine("IsGenericType: {0}", t.IsGenericType);
111 Console.WriteLine("IsGenericTypeDefinition: {0}", t.IsGenericTypeDefinition);
112 Console.WriteLine("ContainsGenericParameters: {0}", t.ContainsGenericParameters);
91 113 }
92 114
93 115 static void DisplayContainerRegistrations(IUnityContainer theContainer) {
94 116 string regName, regType, mapTo, lifetime;
95 117 Console.WriteLine("Container has {0} Registrations:",
96 118 theContainer.Registrations.Count());
97 119 foreach (ContainerRegistration item in theContainer.Registrations) {
98 120 regType = item.RegisteredType.FullName;
99 121 mapTo = item.MappedToType.FullName;
100 122 regName = item.Name ?? "[default]";
101 123 lifetime = item.LifetimeManager.LifetimeType.Name;
102 124 if (mapTo != regType) {
103 125 mapTo = " -> " + mapTo;
104 126 } else {
105 127 mapTo = string.Empty;
106 128 }
107 129 lifetime = lifetime.Substring(0, lifetime.Length - "LifetimeManager".Length);
108 130 Console.WriteLine("+ {0}{1} '{2}' {3}", regType, mapTo, regName, lifetime);
109 131 }
110 132 }
111 133
112 134
113 135 }
114 136 }
@@ -1,68 +1,74
1 1 <?xml version="1.0" encoding="UTF-8"?>
2 2 <container xmlns="http://implab.org/schemas/servicehost/unity.v1.xsd">
3 3 <namespace name="System"/>
4 4 <namespace name="System.Collections.Generic"/>
5 <namespace name="Implab.Components"/>
5 6 <namespace name="Implab.Playground"/>
6 7
7 8 <!-- foo1 -->
8 9 <register name="foo1" type="Foo">
9 10 <property name="Name">
10 11 <value>FOO!</value>
11 12 </property>
12 13 </register>
13 14
14 15 <!-- foo2 -->
15 16 <register name="foo2" type="Foo">
16 17 <property name="Name">
17 18 <value>GOOD</value>
18 19 </property>
19 20 <property name="IntValue">
20 21 <value>2</value>
21 22 </property>
22 23 </register>
23 24
24 25 <register type="Foo">
25 26 <method name="AddRange">
26 27 <array itemsType="Foo">
27 28 <dependency name="foo2"/>
28 29 </array>
29 30 </method>
30 31 </register>
31 32
32 33 <register type="IContainer{}" mapTo="Container{}">
33 34 <constructor/>
34 35 <method name="SetInstance">
35 36 <dependency type="T"/>
36 37 </method>
37 38 <method name="AddRange">
38 39 <array itemsType="T">
39 <dependency name="foo2"/>
40 <dependency name="foo2-bar"/>
40 41 </array>
41 42 </method>
42 43 </register>
43 44
44 45 <register type="List{}">
45 46 <constructor />
46 47 </register>
47 48
48 49 <register type="IContainer{String}" mapTo="Container{String}">
49 50 <constructor/>
50 51 <method name="SetInstance">
51 52 <dependency type="String" name="name1"/>
52 53 </method>
53 54 </register>
54 55
55 56 <serialized type="Foo+Bar">
56 57 <Bar xmlns="" id="1">
57 58 <Name>Baaar</Name>
58 59 </Bar>
59 60 </serialized>
60 61
61 62 <value name="connection1" type="String"><![CDATA[Connect me <here>!]]></value>
62 63 <value name="name1" type="String" value="Hello!"/>
63 64
64 <factory name="foo3" type="FooFactory">
65 <parameter name="FooName"><![CDATA[Wired "" objecty <> name @#$%^&]]></parameter>
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>
66 72 </factory>
67 73
68 74 </container> No newline at end of file
@@ -1,20 +1,20
1 1 using System.Xml.Serialization;
2 2
3 3 namespace Implab.ServiceHost.Unity
4 4 {
5 5 public class ArrayParameterElement : InjectionParameterElement {
6 6
7 7 [XmlAttribute("itemsType")]
8 8 public string ItemsType { get; set; }
9 9
10 10 [XmlElement("dependency", typeof(DependencyParameterElement))]
11 11 [XmlElement("value", typeof(ValueParameterElement))]
12 12 [XmlElement("serialized", typeof(SerializedParameterElement))]
13 13 [XmlElement("default", typeof(DefaultParameterElement))]
14 14 public InjectionParameterElement[] Items { get; set; }
15 15
16 public override void Visit(InjectionValueBuilder builder) {
16 public override void Visit(InjectionParameterBuilder builder) {
17 17 builder.Visit(this);
18 18 }
19 19 }
20 20 } No newline at end of file
@@ -1,14 +1,14
1 1 using System.Xml.Serialization;
2 2
3 3 namespace Implab.ServiceHost.Unity
4 4 {
5 5 [XmlRoot("assembly", Namespace = Schema.ContainerConfigurationNamespace)]
6 6 public class AssemblyElement : AbstractContainerItem {
7 7 [XmlAttribute("name")]
8 8 public string AssemblyName { get; set; }
9 9
10 10 public override void Visit(ContainerBuilder builder) {
11 builder.Visit(this);
11 builder.AddAssembly(AssemblyName);
12 12 }
13 13 }
14 14 } No newline at end of file
@@ -1,118 +1,177
1 1 using System;
2 using System.Collections.Generic;
3 using System.Text.RegularExpressions;
4 using Implab.Diagnostics;
2 using System.Reflection;
3 using Unity;
5 4
6 5 namespace Implab.ServiceHost.Unity {
7 using System.Linq;
8 using System.Reflection;
9 using System.Text;
10 using global::Unity;
11 using global::Unity.Registration;
12 using Implab.Xml;
13 using static Trace<ContainerBuilder>;
14
15 6 public class ContainerBuilder {
16 7
17 8 readonly TypeResolver m_resolver;
18 9
19 10 readonly UnityContainer m_container;
20 11
21 12 readonly ContainerConfigurationSchema m_schema;
22 13
23 14 public UnityContainer Container {
24 15 get {
25 16 return m_container;
26 17 }
27 18 }
28 19
29 20 public ContainerBuilder() : this(null, null) {
30 21 }
31 22
32 23 public ContainerBuilder(UnityContainer container, ContainerConfigurationSchema schema) {
33 24 m_container = container ?? new UnityContainer();
34 25 m_resolver = new TypeResolver();
35 26 m_schema = schema ?? ContainerConfigurationSchema.Default;
36 27 }
37 28
38 29 public Type ResolveType(string typeReference) {
39 return m_resolver.Resolve(typeReference);
30 return m_resolver.Resolve(typeReference, true);
40 31 }
41 32
42 33
43 34 internal void Visit(TypeAbstractRegistration typeRegistration) {
44 35 var registrationType = typeRegistration.GetRegistrationType(ResolveType);
45 36 var implementationType = typeRegistration.GetImplementationType(ResolveType) ?? registrationType;
46 37
47 38 var registrationContext = new TypeRegistrationBuilder(
48 39 m_resolver,
49 40 registrationType,
50 41 implementationType
51 42 );
52 43
53 44 typeRegistration.Visit(registrationContext);
54 45
55 46 m_container.RegisterType(
56 47 registrationContext.RegistrationType,
57 48 registrationContext.ImplementationType,
58 49 typeRegistration.Name,
59 50 registrationContext.Lifetime,
60 51 registrationContext.Injections
61 52 );
62 53 }
63 54
64 55 internal void Visit(InstanceAbstractRegistration instanceRegistration) {
65 56 var registrationType = instanceRegistration.GetRegistrationType(ResolveType);
66 57
67 58 var builder = new InstanceRegistrationBuilder(m_resolver, registrationType);
68 59
69 60 instanceRegistration.Visit(builder);
70 61
71 62 m_container.RegisterInstance(
72 63 builder.ValueBuilder.ValueType,
73 64 instanceRegistration.Name,
74 65 builder.ValueBuilder.Value,
75 66 builder.Lifetime
76 67 );
77 68 }
78 69
79 70 internal void Visit(FactoryAbstractRegistratrion factoryRgistration) {
80 71 var registrationType = factoryRgistration.GetRegistrationType(ResolveType);
81 72
82 73 var builder = new FactoryRegistrationBuilder(registrationType);
83 74
84 75 factoryRgistration.Visit(builder);
85 76
86 77 m_container.RegisterType(
87 78 builder.RegistrationType,
88 79 factoryRgistration.Name,
89 80 builder.Lifetime,
90 81 builder.Factory
91 82 );
92 83 }
93 84
94 internal void Visit(NamespaceElement namespaceElement) {
95 m_resolver.AddNamespace(namespaceElement.Name);
85 public void Visit(ITypeRegistration registration) {
86 Safe.ArgumentNotNull(registration, nameof(registration));
87
88 var registrationType = registration.GetRegistrationType(this);
89 var implementationType = registration.GetImplementationType(this) ?? registrationType;
90
91 if (registrationType == null)
92 throw new Exception($"A type must be specified for the registration {registration.Name}");
93
94 var builder = new TypeRegistrationBuilder(
95 m_resolver,
96 registrationType,
97 implementationType
98 );
99
100 builder.Lifetime = registration.GetLifetime(this);
101
102 if (registration.MemberInjections != null) {
103 foreach(var member in registration.MemberInjections)
104 member.Visit(builder);
105 }
106
107 m_container.RegisterType(
108 builder.RegistrationType,
109 builder.ImplementationType,
110 registration.Name,
111 builder.Lifetime,
112 builder.Injections
113 );
96 114 }
97 115
98 internal void Visit(AssemblyElement assemblyElement) {
99 Assembly.Load(assemblyElement.AssemblyName);
116 public void Visit(IInstanceRegistration registration) {
117 Safe.ArgumentNotNull(registration, nameof(registration));
118
119 var registrationType = registration.GetRegistrationType(this);
120
121 var builder = new InstanceRegistrationBuilder (
122 m_resolver,
123 registrationType
124 );
125
126 builder.Lifetime = registration.GetLifetime(this);
127
128 if (registration.MemberInjections != null) {
129 foreach(var member in registration.MemberInjections)
130 member.Visit(builder.ValueBuilder);
131 }
132
133 if (builder.RegistrationType == null && builder.ValueBuilder.ValueType == null)
134 throw new Exception($"A type must be specified for the registration {registration.Name}");
135
136 m_container.RegisterInstance(
137 builder.RegistrationType ?? builder.ValueBuilder.ValueType,
138 registration.Name,
139 builder.ValueBuilder.Injection,
140 builder.Lifetime
141 );
100 142 }
101 143
102 internal void Visit(IncludeElement includeElement) {
103 Include(includeElement.Href);
144 public void Visit(IFactoryRegistration registration) {
145 Safe.ArgumentNotNull(registration, nameof(registration));
146
147 var registrationType = registration.GetRegistrationType(this);
148
149 var builder = new FactoryRegistrationBuilder(registrationType);
150
151 if (registration.MemberInjections != null) {
152 foreach(var member in registration.MemberInjections)
153 member?.Visit(builder);
154 }
155
156 }
157
158 public void AddNamespace(string ns) {
159 m_resolver.AddNamespace(ns);
160 }
161
162 public void AddAssembly(string assembly) {
163
104 164 }
105 165
106 166 public void Include(string file) {
107 167 var includeContext = new ContainerBuilder(m_container, m_schema);
108 168 includeContext.LoadConfig(file);
109 169 }
110 170
111 171 public void LoadConfig(string file) {
112 172 var config = m_schema.LoadFile(file);
113
114 173 config.Visit(this);
115 174 }
116
175
117 176 }
118 177 } No newline at end of file
@@ -1,69 +1,70
1 1 using System;
2 2 using System.Collections.Generic;
3 3 using System.IO;
4 4 using System.Reflection;
5 5 using System.Xml;
6 6 using System.Xml.Serialization;
7 7 using Implab.Components;
8 8
9 9 namespace Implab.ServiceHost.Unity {
10 10 public class ContainerConfigurationSchema {
11 11
12 12 public static ContainerConfigurationSchema Default { get; private set; } = CreateDefault();
13 13
14 14 readonly LazyAndWeak<XmlSerializer> m_seralizer;
15 15
16 16 readonly XmlAttributeOverrides m_overrides = new XmlAttributeOverrides();
17 17
18 18 readonly XmlAttributes m_containerItems = new XmlAttributes();
19 19
20 20 public XmlSerializer Serializer {
21 21 get {
22 22 return m_seralizer.Value;
23 23 }
24 24 }
25 25
26 26 public ContainerConfigurationSchema() {
27 27 m_overrides.Add(typeof(ContainerElement), nameof(ContainerElement.Items), m_containerItems);
28 28
29 29 m_seralizer = new LazyAndWeak<XmlSerializer>(() => new XmlSerializer(typeof(ContainerElement), m_overrides));
30 30 }
31 31
32 32 public void RegisterContainerElement(Type type, string name) {
33 33 Safe.ArgumentNotNull(type, nameof(type));
34 34 Safe.ArgumentNotEmpty(name, nameof(name));
35 35
36 36 if(!type.IsSubclassOf(typeof(AbstractContainerItem)))
37 37 throw new Exception($"RegisterContainerElement '{name}': {type} must be subclass of {typeof(AbstractContainerItem)}");
38 38
39 39 m_containerItems.XmlElements.Add(
40 40 new XmlElementAttribute(name, type)
41 41 );
42 42 }
43 43
44 44 public void RegisterContainerElement<T>(string name) where T : AbstractContainerItem {
45 45 RegisterContainerElement(typeof(T), name);
46 46 }
47 47
48 48 public ContainerElement LoadFile(string file) {
49 49 using (var reader = XmlReader.Create(file)) {
50 50 return (ContainerElement)Serializer.Deserialize(reader);
51 51 }
52 52 }
53 53
54 54 static ContainerConfigurationSchema CreateDefault() {
55 55 var schema = new ContainerConfigurationSchema();
56 56
57 57 schema.RegisterContainerElement<RegisterElement>("register");
58 schema.RegisterContainerElement<FactoryElement>("factory");
58 59 schema.RegisterContainerElement<SerializedElement>("serialized");
59 60 schema.RegisterContainerElement<ValueElement>("value");
60 61 schema.RegisterContainerElement<IncludeElement>("include");
61 62 schema.RegisterContainerElement<AssemblyElement>("assembly");
62 63 schema.RegisterContainerElement<NamespaceElement>("namespace");
63 64
64 65 return schema;
65 66 }
66 67
67 68
68 69 }
69 70 } No newline at end of file
@@ -1,13 +1,13
1 1 namespace Implab.ServiceHost.Unity
2 2 {
3 3 public class DefaultParameterElement : InjectionParameterElement {
4 4 public string Value {
5 5 get { return null; }
6 6 }
7 7
8 public override void Visit(InjectionValueBuilder builder) {
8 public override void Visit(InjectionParameterBuilder builder) {
9 9 var type = builder.ResolveInjectedValueType(TypeName);
10 10 builder.SetValue(type, Safe.CreateDefaultValue(type));
11 11 }
12 12 }
13 13 } No newline at end of file
@@ -1,17 +1,17
1 1 using System.Xml.Serialization;
2 2
3 3 namespace Implab.ServiceHost.Unity {
4 4 public class DependencyParameterElement : InjectionParameterElement {
5 5
6 6 [XmlAttribute("name")]
7 7 public string DependencyName { get; set; }
8 8
9 9 [XmlAttribute("optional")]
10 10 public bool Optional { get; set; }
11 11
12 public override void Visit(InjectionValueBuilder builder) {
12 public override void Visit(InjectionParameterBuilder builder) {
13 13 var type = builder.ResolveInjectedValueType(TypeName);
14 14 builder.SetDependencyReference(type, DependencyName, Optional);
15 15 }
16 16 }
17 17 } No newline at end of file
@@ -1,36 +1,54
1 1 using System;
2 2 using Implab.Components;
3 3 using Unity;
4 4 using Unity.Injection;
5 5 using Unity.Registration;
6 6
7 7 namespace Implab.ServiceHost.Unity
8 8 {
9 9 public class FactoryRegistrationBuilder : RegistrationBuilder {
10 10
11 11 internal InjectionMember Factory { get; private set; }
12 12
13 13 internal FactoryRegistrationBuilder(Type registrationType) : base(registrationType) {
14 14 }
15 15
16 /// <summary>
17 /// Задает делегат, который будет использоваться в качестве фабрики
18 /// для создания экземпляров, параметры делагата будет заполнены
19 /// соответствующими зависимостями.
20 /// </summary>
21 /// <param name="factory">Фабрика для создания экземпляров.</param>
16 22 public void SetFactoryDelegate(Delegate factory) {
17 23 Safe.ArgumentNotNull(factory, nameof(factory));
18 24
19 25 Factory = new DelegateInjectionFactory(factory);
20 26 }
21 27
28 /// <summary>
29 /// Указывает зависимость типа <typeparamref name="T"/> с именем
30 /// <paramref name="dependencyName"/>, которая будет передана в качетве
31 /// параметра делегату <paramref name="factory"/>
32 /// </summary>
33 /// <param name="dependencyName">Имя зависимости</param>
34 /// <param name="factory">Фабрика для создания экземпляра</param>
22 35 public void SetFactoryDependency<T>(string dependencyName, Func<T, object> factory) {
23 36 Safe.ArgumentNotNull(factory, nameof(factory));
24 37
25 38 Factory = new InjectionFactory((c,t,name) => {
26 39 var backend = c.Resolve<T>(dependencyName);
27 40 return factory(backend);
28 41 });
29 42 }
30 43
44 /// <summary>
45 /// Указывает зависимость, реализующую интерфейс <see cref="IFactory{TObj}"/>,
46 /// которая будет использоваться в качестве фабрики для создания объектов
47 /// </summary>
48 /// <param name="dependencyName"></param>
31 49 public void SetFactoryDependency<TFac, TObj>(string dependencyName) where TFac : IFactory<TObj> {
32 50
33 51 Factory = new InjectionFactory(c => c.Resolve<TFac>(dependencyName).Create());
34 52 }
35 53 }
36 54 } No newline at end of file
@@ -1,13 +1,13
1 1 using System.Xml.Serialization;
2 2
3 3 namespace Implab.ServiceHost.Unity {
4 4 [XmlRoot("include", Namespace = Schema.ContainerConfigurationNamespace)]
5 5 public class IncludeElement : AbstractContainerItem {
6 6 [XmlAttribute("href")]
7 7 public string Href { get; set; }
8 8
9 public override void Visit(ContainerBuilder context) {
10 context.Visit(this);
9 public override void Visit(ContainerBuilder builder) {
10 builder.Include(Href);
11 11 }
12 12 }
13 13 } No newline at end of file
@@ -1,12 +1,12
1 1 using System;
2 2 using System.Xml.Serialization;
3 3
4 4 namespace Implab.ServiceHost.Unity {
5 5 public abstract class InjectionParameterElement {
6 6
7 7 [XmlAttribute("type")]
8 8 public string TypeName { get; set; }
9 9
10 public abstract void Visit(InjectionValueBuilder builder);
10 public abstract void Visit(InjectionParameterBuilder builder);
11 11 }
12 12 } No newline at end of file
@@ -1,89 +1,92
1 1 using System;
2 2 using System.Collections.Generic;
3 3 using System.ComponentModel;
4 4 using System.Linq;
5 5 using System.Xml.Serialization;
6 6 using Unity.Injection;
7 7
8 8 namespace Implab.ServiceHost.Unity {
9 9
10 public class InjectionValueBuilder {
10 public class InjectionParameterBuilder {
11 11
12 12 readonly TypeResolver m_resolver;
13 13
14 14 public Type DefaultType { get; private set; }
15 15
16 16 public Type ValueType { get; private set; }
17 17
18 18 public object Value { get; set; }
19 19
20 20 internal InjectionParameterValue Injection {
21 21 get {
22 22 if (Value != null)
23 23 return InjectionParameterValue.ToParameter(Value);
24 24
25 25 return new InjectionParameter(ValueType, null);
26 26 }
27 27 }
28 28
29 internal InjectionValueBuilder(TypeResolver resolver, Type defaultType) {
29 internal InjectionParameterBuilder(TypeResolver resolver, Type defaultType) {
30 30 m_resolver = resolver;
31 31 DefaultType = defaultType;
32 32 }
33 33
34 34 public Type ResolveInjectedValueType(string typeSpec) {
35 35 if (string.IsNullOrEmpty(typeSpec)) {
36 36 if (DefaultType == null)
37 37 throw new Exception("The type must be specified");
38 38 return DefaultType;
39 39 }
40 return m_resolver.Resolve(typeSpec);
40 return m_resolver.Resolve(typeSpec, true);
41 41 }
42 42
43 43 public Type ResolveType(string typeSpec) {
44 return m_resolver.Resolve(typeSpec);
44 return m_resolver.Resolve(typeSpec, true);
45 45 }
46 46
47 47 public void SetValue(Type type, object value) {
48 48 ValueType = type;
49 49 Value = value;
50 50 }
51 51
52 52 public void SetValue<T>(T value) {
53 53 SetValue(typeof(T), value);
54 54 }
55 55
56 56 public void SetDependencyReference(Type type, string name, bool optional) {
57 57 ValueType = type;
58 58 Value = optional ? (object)new OptionalParameter(type, name) : new ResolvedParameter(type, name);
59 59 }
60 60
61 61 internal void Visit(ArrayParameterElement arrayParameter) {
62 62 Type itemsType = null;
63 63 var arrayType = string.IsNullOrEmpty(arrayParameter.TypeName) ? null : ResolveType(arrayParameter.TypeName);
64 64
65 65 if (!string.IsNullOrEmpty(arrayParameter.ItemsType)) {
66 66 itemsType = ResolveType(arrayParameter.ItemsType);
67 67 if (arrayType == null)
68 68 arrayType = itemsType.MakeArrayType();
69 69 } else {
70 70 itemsType = arrayType?.GetInterface(typeof(IEnumerable<>).FullName)?.GetGenericArguments()[0];
71 71 }
72 72
73 73 if (itemsType == null)
74 74 throw new Exception("Failed to determine array elements type");
75 75
76 76 InjectionParameterValue[] injections = (arrayParameter.Items ?? new InjectionParameterElement[0])
77 77 .Select(x => {
78 var builder = new InjectionValueBuilder(m_resolver, itemsType);
78 var builder = new InjectionParameterBuilder(m_resolver, itemsType);
79 79 x.Visit(builder);
80 80 return builder.Injection;
81 81 })
82 82 .ToArray();
83 83
84 var array = itemsType.IsGenericParameter ? (object)new GenericResolvedArrayParameter(itemsType.Name, injections) : new ResolvedArrayParameter(itemsType, injections);
84 var array = itemsType.IsGenericParameter ?
85 (object)new GenericResolvedArrayParameter(itemsType.Name, injections) :
86 new ResolvedArrayParameter(itemsType, injections);
87
85 88 ValueType = arrayType;
86 89 Value = array;
87 90 }
88 91 }
89 92 } No newline at end of file
@@ -1,13 +1,13
1 1 using System;
2 2
3 3 namespace Implab.ServiceHost.Unity
4 4 {
5 5 public class InstanceRegistrationBuilder : RegistrationBuilder {
6 6
7 public InjectionValueBuilder ValueBuilder { get; private set; }
7 public InjectionParameterBuilder ValueBuilder { get; private set; }
8 8
9 9 internal InstanceRegistrationBuilder(TypeResolver typeResolver, Type registrationType) : base(registrationType) {
10 ValueBuilder = new InjectionValueBuilder(typeResolver, registrationType);
10 ValueBuilder = new InjectionParameterBuilder(typeResolver, registrationType);
11 11 }
12 12 }
13 13 } No newline at end of file
@@ -1,15 +1,15
1 1 using System.Xml.Serialization;
2 2
3 3 namespace Implab.ServiceHost.Unity
4 4 {
5 5 [XmlRoot("namespace", Namespace = Schema.ContainerConfigurationNamespace)]
6 6 public class NamespaceElement : AbstractContainerItem {
7 7
8 8 [XmlAttribute("name")]
9 9 public string Name { get; set; }
10 10
11 public override void Visit(ContainerBuilder context) {
12 context.Visit(this);
11 public override void Visit(ContainerBuilder builder) {
12 builder.AddNamespace(Name);
13 13 }
14 14 }
15 15 } No newline at end of file
@@ -1,33 +1,33
1 1 using System;
2 2 using System.Xml;
3 3 using System.Xml.Schema;
4 4 using System.Xml.Serialization;
5 5
6 6 namespace Implab.ServiceHost.Unity
7 7 {
8 8 public class SerializedParameterElement : InjectionParameterElement {
9 9 [XmlAttribute("href")]
10 10 public string Location { get; set; }
11 11
12 12 [XmlAnyElement]
13 13 public XmlElement[] Content { get; set; }
14 14
15 15 public XmlReader GetReader() {
16 16 if (!string.IsNullOrEmpty(Location))
17 17 return XmlReader.Create(Location);
18 18 if (Content != null && Content.Length > 0)
19 19 return Content[0].CreateNavigator().ReadSubtree();
20 20
21 21 throw new Exception("No content found, expected XML document");
22 22 }
23 23
24 public override void Visit(InjectionValueBuilder builder) {
24 public override void Visit(InjectionParameterBuilder builder) {
25 25 var type = builder.ResolveInjectedValueType(TypeName);
26 26
27 27 var serializer = new XmlSerializer(type);
28 28 using(var reader = GetReader())
29 29 builder.SetValue(type, serializer.Deserialize(reader));
30 30
31 31 }
32 32 }
33 33 } No newline at end of file
@@ -1,58 +1,182
1 1 using System;
2 2 using System.Linq;
3 3 using System.Text;
4 4
5 5 namespace Implab.ServiceHost.Unity {
6 public class TypeReference {
7 public string TypeName { get; set; }
8
9 public string Namespace { get; set; }
10
11 public TypeReference[] GenericParameters { get; set; }
12
13 public bool IsArray { get; set; }
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 {
14 51
15 public bool IsOpenGeneric {
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 {
16 85 get {
17 return GenericParameters!=null && GenericParameters.Contains(null);
18 }
19 }
20
21 public bool IsGeneric {
22 get {
23 return GenericParameters != null && GenericParameters.Length > 0;
86 return GenericParametersCount != 0 ? $"{Name}`{GenericParametersCount}" : Name;
24 87 }
25 88 }
26 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>
27 133 public override string ToString() {
28 134 var builder = new StringBuilder();
29
30 if (!string.IsNullOrEmpty(Namespace)) {
31 builder.Append(Namespace);
32 builder.Append('.');
33 }
34
35 if (!string.IsNullOrEmpty(TypeName)) {
36 builder.Append(TypeName);
37 } else {
38 builder.Append("__unnamed__");
39 }
40
41 if (GenericParameters != null && GenericParameters.Length > 0) {
42 builder.Append('{');
43 for(var i = 0; i < GenericParameters.Length; i++) {
44 if (i > 0)
45 builder.Append(',');
46 builder.Append(GenericParameters[i]);
47 }
48 builder.Append('}');
49 }
50
135 WriteTypeName(builder);
136 WriteTypeParams(builder);
51 137 return builder.ToString();
52 138 }
53 public static TypeReference Parse(string text) {
54 var parser = new TypeReferenceParser(text);
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);
55 178 return parser.Parse();
56 179 }
180
57 181 }
58 182 } No newline at end of file
@@ -1,175 +1,245
1 1 using System;
2 2 using System.Collections.Generic;
3 using System.Linq;
3 4 using System.Text.RegularExpressions;
4 5
5 6 namespace Implab.ServiceHost.Unity {
6 7 internal class TypeReferenceParser {
7 8 enum TokenType {
8 9 None,
9 10
10 11 Word,
11 12
12 13 Dot,
13 14
14 15 Comma,
15 16
16 17 OpenList,
17 18
18 19 CloseList,
19 20
20 21 OpenArray,
21 22
22 23 CloseArray,
23 24
25 Plus,
26
24 27 Eof
25 28 }
26 29
27 readonly Regex _tokens = new Regex(@"([\w\+]+)|\s*([\.{},\[\]])\s*");
30 readonly Regex _tokens = new Regex(@"\G(?:([\w]+)|\s*([\+\.{},\[\]])\s*)", RegexOptions.Compiled);
28 31
29 32 TokenType m_token;
30 33
31 34 string m_tokenValue;
32 35
33 36 int m_pos;
34 37
35 38 int m_tokenPos;
36 39
37 40 readonly string m_text;
38 41
39 42 TokenType Token { get { return m_token; } }
40 43
41 44 string TokenValue { get { return m_tokenValue; } }
42 45
43 46 int TokenPos { get { return m_tokenPos; } }
44 47
45 48 public TypeReferenceParser(string text) {
46 49 Safe.ArgumentNotEmpty(text, nameof(text));
47 50 m_text = text;
48 51 }
49 52
50 53 bool ReadToken() {
51 54 if (m_pos >= m_text.Length) {
52 55 m_token = TokenType.Eof;
53 56 m_tokenValue = null;
54 57 return false;
55 58 }
56 59
57 60 var m = _tokens.Match(m_text, m_pos);
58 61
59 62 if (m.Success) {
60 63 m_tokenPos = m_pos;
61 64 m_pos += m.Length;
62 65 if (m.Groups[1].Success) {
63 66 m_token = TokenType.Word;
64 67 m_tokenValue = m.Groups[1].Value;
65 68 } else if (m.Groups[2].Success) {
66 69 m_tokenValue = null;
67 70 switch (m.Groups[2].Value) {
68 71 case "{":
69 72 m_token = TokenType.OpenList;
70 73 break;
71 74 case "}":
72 75 m_token = TokenType.CloseList;
73 76 break;
74 77 case ".":
75 78 m_token = TokenType.Dot;
76 79 break;
77 80 case ",":
78 81 m_token = TokenType.Comma;
79 82 break;
80 83 case "[":
81 84 m_token = TokenType.OpenArray;
82 85 break;
83 86 case "]":
84 87 m_token = TokenType.CloseArray;
85 88 break;
89 case "+":
90 m_token = TokenType.Plus;
91 break;
86 92 }
87 93 }
88 94 return true;
89 95 }
90 96 throw new FormatException($"Failed to parse '{m_text}' at pos {m_pos}");
91 97 }
92 98
93 99 public TypeReference Parse() {
94 100 var result = ReadTypeReference();
95 101 if (Token != TokenType.Eof)
96 102 ThrowUnexpectedToken();
97 103 return result;
98 104 }
99 105
100 string[] ReadTypeName() {
106 string[] ReadQTypeName() {
101 107 var parts = new List<string>();
102 108
103 109 string current = null;
104 110 bool stop = false;
105 111 while ((!stop) && ReadToken()) {
106 112 switch (Token) {
107 113 case TokenType.Word:
108 114 if (current != null)
109 115 ThrowUnexpectedToken();
110 116 current = TokenValue;
111 117 break;
112 118 case TokenType.Dot:
113 119 if (current == null)
114 120 ThrowUnexpectedToken();
115 121 parts.Add(current);
116 122 current = null;
117 123 break;
118 124 default:
119 125 stop = true;
120 126 break;
121 127 }
122 128 }
123 129 if (current != null)
124 130 parts.Add(current);
125 131
126 132 if (parts.Count == 0)
127 133 return null;
128 134
129 135 return parts.ToArray();
130 136 }
131 137
138 string ReadNQTypeName() {
139 ReadToken();
140 if (Token != TokenType.Word)
141 ThrowUnexpectedToken();
142 return TokenValue;
143 }
144
132 145 TypeReference ReadTypeReference() {
133 146
134 var parts = ReadTypeName();
147 var parts = ReadQTypeName();
135 148 if (parts == null)
136 149 return null;
137 150
138 var typeReference = new TypeReference {
139 Namespace = string.Join(".", parts, 0, parts.Length - 1),
140 TypeName = parts[parts.Length - 1]
141 };
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 );
142 182
143 switch (Token) {
144 case TokenType.OpenList:
145 typeReference.GenericParameters = ReadTypeReferenceList();
146 if (Token != TokenType.CloseList)
147 ThrowUnexpectedToken();
148 ReadToken();
149 break;
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();
150 216 }
151 217
152 218 return typeReference;
153 219 }
154 220
155 int CountDimentions() {
156 return 0;
221 int CountRank() {
222 int rank = 0;
223 do {
224 rank++;
225 } while(ReadToken() && Token == TokenType.Comma);
226 return rank;
157 227 }
158 228
159 229 TypeReference[] ReadTypeReferenceList() {
160 230 var list = new List<TypeReference>();
161 231
162 232 do {
163 233 var typeReference = ReadTypeReference();
164 234 list.Add(typeReference);
165 235 } while (Token == TokenType.Comma);
166 236
167 237 return list.ToArray();
168 238 }
169 239
170 240 void ThrowUnexpectedToken() {
171 241 throw new FormatException($"Unexpected '{Token}' at pos {TokenPos}: -->{m_text.Substring(TokenPos, Math.Min(m_text.Length - TokenPos, 10))}");
172 242 }
173 243
174 244 }
175 245 } No newline at end of file
@@ -1,77 +1,75
1 1 using System;
2 2 using System.Collections.Generic;
3 3 using System.Linq;
4 4 using Unity.Injection;
5 5 using Unity.Registration;
6 6
7 7 namespace Implab.ServiceHost.Unity {
8 8 public class TypeRegistrationBuilder : RegistrationBuilder {
9 9
10 10 readonly TypeResolver m_resolver;
11 11
12 12 readonly List<InjectionMember> m_injections = new List<InjectionMember>();
13 13
14 14 internal InjectionMember[] Injections { get { return m_injections.ToArray(); } }
15 15
16 16 public Type ImplementationType {
17 17 get;
18 18 private set;
19 19 }
20 20
21 21 internal TypeRegistrationBuilder(TypeResolver resolver, Type registrationType, Type implementationType) : base(registrationType) {
22 22 ImplementationType = implementationType;
23 23
24 24 // when registering a generic mapping, register all generic parameter names as local types
25 25 if (ImplementationType.IsGenericTypeDefinition) {
26 26 m_resolver = new TypeResolver(resolver);
27 27
28 28 foreach (var p in ImplementationType.GetGenericArguments())
29 29 m_resolver.AddMapping(p.Name, p);
30 30 } else {
31 31 m_resolver = resolver;
32 32 }
33 33 }
34 34
35 35 internal void Visit(ConstructorInjectionElement constructorInjection) {
36 36
37 37
38 38 var parameters = constructorInjection.Parameters?
39 39 .Select(x => {
40 var valueBuilder = new InjectionValueBuilder(m_resolver, null);
40 var valueBuilder = new InjectionParameterBuilder(m_resolver, null);
41 41 x.Visit(valueBuilder);
42 42 return valueBuilder.Injection;
43 43 })
44 44 .ToArray();
45 45
46 46 var injection = parameters != null ? new InjectionConstructor(parameters) : new InjectionConstructor();
47 47 m_injections.Add(injection);
48 48 }
49 49
50 50 internal void Visit(MethodInjectionElement methodInjection) {
51 var valueContext = new InjectionValueBuilder(m_resolver, null);
52
53 51 var parameters = methodInjection.Parameters?
54 52 .Select(x => {
55 var valueBuilder = new InjectionValueBuilder(m_resolver, null);
53 var valueBuilder = new InjectionParameterBuilder(m_resolver, null);
56 54 x.Visit(valueBuilder);
57 55 return valueBuilder.Injection;
58 56 })
59 57 .ToArray();
60 58
61 59 var injection = parameters != null ? new InjectionMethod(methodInjection.Name, parameters) : new InjectionMethod(methodInjection.Name);
62 60 m_injections.Add(injection);
63 61 }
64 62
65 63 internal void Visit(PropertyInjectionElement propertyInjection) {
66 64 if (propertyInjection.Value == null)
67 65 throw new Exception($"A value value must be specified for the property '{propertyInjection.Name}'");
68 66
69 var propertyType = RegistrationType.GetProperty(propertyInjection.Name)?.PropertyType;
70 var valueContext = new InjectionValueBuilder(m_resolver, propertyType);
67 var propertyType = ImplementationType.GetProperty(propertyInjection.Name)?.PropertyType;
68 var valueContext = new InjectionParameterBuilder(m_resolver, propertyType);
71 69
72 70 propertyInjection.Value.Visit(valueContext);
73 71 var injection = new InjectionProperty(propertyInjection.Name, valueContext.Injection);
74 72 m_injections.Add(injection);
75 73 }
76 74 }
77 75 } No newline at end of file
@@ -1,125 +1,98
1 1 using System;
2 2 using System.Collections.Generic;
3 3 using System.Linq;
4 4 using System.Text;
5 5 using System.Text.RegularExpressions;
6 6 using Implab.Diagnostics;
7 7
8 8 namespace Implab.ServiceHost.Unity {
9 using System.Diagnostics;
9 10 using static Trace<TypeResolver>;
10 11 public class TypeResolver {
11 12 readonly Dictionary<string, Type> m_cache = new Dictionary<string, Type>();
12 13
13 14 Regex _nsRx = new Regex(@"^\w+(\.\w+)*$", RegexOptions.Compiled);
14 15 readonly LinkedList<string> m_namespases = new LinkedList<string>();
15 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 var typeReference = TypeReference.Parse(typeSpec);
31 return Resolve(typeReference, throwOnFail);
32 }
33
16 34 LinkedListNode<string> m_insertAt;
17 35
18 36 readonly TypeResolver m_parent;
19 37
20 38 public TypeResolver() : this(null) {
21
22 39 }
23 40
24 41 public TypeResolver(TypeResolver parent) {
25 42 m_parent = parent;
26 43 m_insertAt = new LinkedListNode<string>(string.Empty);
27 44 m_namespases.AddFirst(m_insertAt);
28 45 }
29 46
30 47 public void AddNamespace(string ns) {
31 48 Safe.ArgumentMatch(ns, nameof(ns), _nsRx);
32 49 if (m_insertAt != null)
33 50 m_namespases.AddAfter(m_insertAt, ns);
34 51 else
35 52 m_namespases.AddFirst(ns);
36 53 }
37 54
38 55 public void AddMapping(string typeName, Type type) {
39 56 Safe.ArgumentNotEmpty(typeName, nameof(typeName));
40 57 Safe.ArgumentNotNull(type, nameof(type));
41 58
42 59 m_cache[typeName] = type;
43 60 }
44 61
45 public Type Resolve(TypeReference reference) {
46 var args = reference.IsGeneric && !reference.IsOpenGeneric ? reference.GenericParameters?.Select(Resolve).ToArray() : null;
47 var argc = reference.IsGeneric ? reference.GenericParameters.Length : 0;
62 Type ProbeInNamespaces(string localName) {
48 63
49 64 Type resolved;
50 if (!m_cache.TryGetValue(reference.ToString(), out resolved)) {
51 resolved = ResolveInternal(reference, args, argc);
52 if (resolved == null)
53 throw new Exception($"Failed to resolve {reference}");
54 m_cache[reference.ToString()] = resolved;
65 if (!m_cache.TryGetValue(localName, out resolved)) {
66 foreach (var ns in m_namespases) {
67 var typeName = string.IsNullOrEmpty(ns) ? localName : $"{ns}.{localName}";
68 resolved = Probe(typeName);
69 if (resolved != null) {
70 Log($"Probe '{localName}' -> '{resolved.FullName}'");
71 break;
72 }
73 }
74
75 if (resolved == null && m_parent != null)
76 resolved = m_parent.ProbeInNamespaces(localName);
77
78 if(resolved == null)
79 Log($"Probe '{localName}' failed");
80
81 m_cache[localName] = resolved;
55 82 }
56 83
57 84 return resolved;
58 85 }
59 86
60 public Type Resolve(string typeSpec) {
61 return Resolve(TypeReference.Parse(typeSpec));
62 }
63
64 Type ResolveInternal(TypeReference reference, Type[] args, int argc) {
65 var resolved = ProbeInNamespaces(
66 String.Join(".", new[] { reference.Namespace, reference.TypeName }.Where(x => !string.IsNullOrEmpty(x))),
67 args,
68 argc,
69 reference.IsArray,
70 reference.ToString()
71 );
72
73 if (resolved == null && m_parent != null)
74 resolved = m_parent.ResolveInternal(reference, args, argc);
75
76 return resolved;
77 }
78
79 public Type ProbeInNamespaces(string localName, Type[] args, int argc, bool isArray, string referenceName) {
80 foreach (var ns in m_namespases) {
81 var typeName = FormatName(new[] { ns, localName }, argc);
82
83 var resolved = Probe(typeName);
84 if (resolved != null) {
85 if (args != null && args.Length > 0) {
86 resolved = resolved.MakeGenericType(args);
87 }
88
89 if (isArray)
90 resolved = resolved.MakeArrayType();
91
92 Log("Probe succeed {0} in '{1}': {2} -> {3}", referenceName, ns, typeName, resolved.AssemblyQualifiedName);
93 return resolved;
94 } else {
95 Log("Probe failed {0} in '{1}': {2}", referenceName, ns, typeName);
96 }
97 }
98
99 return null;
100 }
101
102 87 Type Probe(string typeName) {
103 88 var assemblies = AppDomain.CurrentDomain.GetAssemblies();
104 89
105 90 foreach (var assembly in assemblies) {
106 91 var type = assembly.GetType(typeName);
107 92 if (type != null)
108 93 return type;
109 94 }
110 95 return null;
111 96 }
112
113 string FormatName(string[] parts, int argc) {
114 var builder = new StringBuilder();
115
116 builder.Append(String.Join(".", parts.Where(x => !string.IsNullOrEmpty(x))));
117 if (argc > 0) {
118 builder.Append('`');
119 builder.Append(argc);
120 }
121
122 return builder.ToString();
123 }
124 97 }
125 98 } No newline at end of file
@@ -1,21 +1,21
1 1 using System.ComponentModel;
2 2 using System.Xml.Serialization;
3 3
4 4 namespace Implab.ServiceHost.Unity {
5 5 public class ValueParameterElement : InjectionParameterElement {
6 6 [XmlAttribute("value")]
7 7 public string Value { get; set; }
8 8
9 9 [XmlText]
10 10 public string Text { get; set; }
11 11
12 12 string GetTextValue() {
13 13 return string.IsNullOrEmpty(Value) ? Text : Value;
14 14 }
15 15
16 public override void Visit(InjectionValueBuilder builder) {
16 public override void Visit(InjectionParameterBuilder builder) {
17 17 var type = builder.ResolveInjectedValueType(TypeName);
18 18 builder.SetValue(type, TypeDescriptor.GetConverter(type).ConvertFromString(GetTextValue()));
19 19 }
20 20 }
21 21 } No newline at end of file
@@ -1,96 +1,93
1 1 using System;
2 2 using System.Collections.Generic;
3 3 using System.IO;
4 4 using System.Linq;
5 5 using System.Reflection;
6 6 using System.Text;
7 7 using System.Threading.Tasks;
8 8 using System.Xml;
9 9 using System.Xml.Linq;
10 10 using System.Xml.Serialization;
11 11
12 12 namespace Implab.Xml {
13 13 public static class SerializationHelpers {
14 14 public static string SerializeAsString<T>(T obj) {
15 return SerializersPool<T>.Instance.SerializeAsString(obj);
15 return XmlDefaultSerializer<T>.Instance.SerializeAsString(obj);
16 16 }
17 17
18 18 public static void Serialize<T>(XmlWriter writer, T obj) {
19 SerializersPool<T>.Instance.Serialize(writer, obj);
19 XmlDefaultSerializer<T>.Instance.Serialize(writer, obj);
20 20 }
21 21
22 22 public static XmlDocument SerializeAsXmlDocument<T>(T obj) {
23 23 var doc = new XmlDocument();
24 24 using (var writer = doc.CreateNavigator().AppendChild()) {
25 SerializersPool<T>.Instance.Serialize(writer, obj);
25 XmlDefaultSerializer<T>.Instance.Serialize(writer, obj);
26 26 }
27 27 return doc;
28 28 }
29 29
30 30 public static XDocument SerializeAsXDocument<T>(T obj) {
31 31 var doc = new XDocument();
32 32 using (var writer = doc.CreateWriter()) {
33 SerializersPool<T>.Instance.Serialize(writer, obj);
33 XmlDefaultSerializer<T>.Instance.Serialize(writer, obj);
34 34 }
35 35 return doc;
36 36 }
37 37
38 38 public static void SerializeToFile<T>(string file, T obj) {
39 using (var writer = File.CreateText(file))
40 SerializersPool<T>.Instance.Serialize(writer, obj);
39 XmlDefaultSerializer<T>.Instance.SerializeToFile(obj, file);
41 40 }
42 41
43 42 public static void SerializeToElementChild<T>(XmlElement element, T obj) {
44 using(var writer = element.CreateNavigator().AppendChild())
45 SerializersPool<T>.Instance.Serialize(writer, obj);
43 XmlDefaultSerializer<T>.Instance.Serialize(obj, element);
46 44 }
47 45
48 46 public static T Deserialize<T>(XmlReader reader) {
49 return SerializersPool<T>.Instance.Deserialize(reader);
47 return (T)XmlDefaultSerializer<T>.Instance.Deserialize(reader);
50 48 }
51 49
52 50 public static T DeserializeFromFile<T>(string file) {
53 using(var reader = XmlReader.Create(File.OpenText(file)))
54 return Deserialize<T>(reader);
51 return (T)XmlDefaultSerializer<T>.Instance.DeserializeFromFile(file);
55 52 }
56 53
57 54 public static T DeserializeFromString<T>(string data) {
58 return SerializersPool<T>.Instance.DeserializeFromString(data);
55 return (T)XmlDefaultSerializer<T>.Instance.DeserializeFromString(data);
59 56 }
60 57
61 58 public static T DeserializeFromXmlNode<T>(XmlNode node) {
62 59 Safe.ArgumentNotNull(node, nameof(node));
63 60 using (var reader = node.CreateNavigator().ReadSubtree())
64 return SerializersPool<T>.Instance.Deserialize(reader);
61 return (T)XmlDefaultSerializer<T>.Instance.Deserialize(reader);
65 62 }
66 63
67 64 public static T DeserializeJson<T>(TextReader textReader) {
68 65 var options = new JsonXmlReaderOptions {
69 66 NamespaceUri = typeof(T).GetCustomAttribute<XmlRootAttribute>()?.Namespace,
70 67 RootName = typeof(T).Name,
71 68 FlattenArrays = true
72 69 };
73 70
74 using(var reader = JsonXmlReader.CreateJsonXmlReader(textReader, options))
71 using (var reader = JsonXmlReader.CreateJsonXmlReader(textReader, options))
75 72 return Deserialize<T>(reader);
76 73 }
77 74
78 75 public static T DeserializeJsonFromString<T>(string data) {
79 using(var reader = new StringReader(data)) {
76 using (var reader = new StringReader(data)) {
80 77 return DeserializeJson<T>(reader);
81 78 }
82 79 }
83 80
84 81 public static void SerializeJson<T>(TextWriter writer, T obj) {
85 82 var doc = SerializeAsXmlDocument(obj);
86 83 XmlToJson.Default.Transform(doc, null, writer);
87 84 }
88 85
89 86 public static string SerializeJsonAsString<T>(T obj) {
90 using(var writer = new StringWriter()) {
87 using (var writer = new StringWriter()) {
91 88 SerializeJson(writer, obj);
92 89 return writer.ToString();
93 90 }
94 91 }
95 92 }
96 93 }
@@ -1,76 +1,77
1 1 using Implab.Components;
2 2 using System;
3 3 using System.Collections.Generic;
4 4 using System.IO;
5 5 using System.Linq;
6 6 using System.Text;
7 7 using System.Threading.Tasks;
8 8 using System.Xml;
9 9 using System.Xml.Serialization;
10 10
11 11 namespace Implab.Xml {
12 [Obsolete("this class will be removed, use XmlDefaultSerializer")]
12 13 public class SerializersPool<T> : ObjectPool<XmlSerializer> {
13 14
14 15 static readonly SerializersPool<T> _instance = new SerializersPool<T>();
15 16
16 17 public static SerializersPool<T> Instance {
17 18 get { return _instance; }
18 19 }
19 20
20 21 #region implemented abstract members of ObjectPool
21 22 protected override XmlSerializer CreateInstance() {
22 23 return new XmlSerializer(typeof(T));
23 24 }
24 25 #endregion
25 26
26 27 public T DeserializeFromString(string data) {
27 28 using (var reader = new StringReader(data)) {
28 29 return Deserialize(reader);
29 30 }
30 31 }
31 32
32 33 public T Deserialize(TextReader reader) {
33 34 var sr = Allocate();
34 35 try {
35 36 return (T)sr.Deserialize(reader);
36 37 } finally {
37 38 Release(sr);
38 39 }
39 40 }
40 41
41 42 public T Deserialize(XmlReader reader) {
42 43 var sr = Allocate();
43 44 try {
44 45 return (T)sr.Deserialize(reader);
45 46 } finally {
46 47 Release(sr);
47 48 }
48 49 }
49 50
50 51 public string SerializeAsString(T data) {
51 52 using (var writer = new StringWriter()) {
52 53 Serialize(writer, data);
53 54 return writer.ToString();
54 55 }
55 56 }
56 57
57 58 public void Serialize(TextWriter writer, T data) {
58 59 var sr = Allocate();
59 60 try {
60 61 sr.Serialize(writer, data);
61 62 } finally {
62 63 Release(sr);
63 64 }
64 65 }
65 66
66 67 public void Serialize(XmlWriter writer, T data) {
67 68 var sr = Allocate();
68 69 try {
69 70 sr.Serialize(writer, data);
70 71 } finally {
71 72 Release(sr);
72 73 }
73 74 }
74 75
75 76 }
76 77 }
General Comments 3
Under Review
author

Auto status change to "Under Review"

Approved
author

ok, latest stable version should be in default

You need to be logged in to leave comments. Login now