Skip to content

Commit 1635b86

Browse files
author
Travis Illig
committed
Fix #26: Type conversion now uses invariant culture.
1 parent 94f35ac commit 1635b86

5 files changed

Lines changed: 192 additions & 110 deletions

File tree

‎src/Autofac.Configuration/Util/TypeManipulation.cs‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,22 +129,22 @@ public static object ChangeToCompatibleType(object value, Type destinationType,
129129
converter = GetTypeConverterFromName(converterAttribute.ConverterTypeName);
130130
if (converter.CanConvertFrom(value.GetType()))
131131
{
132-
return converter.ConvertFrom(value);
132+
return converter.ConvertFrom(null, CultureInfo.InvariantCulture, value);
133133
}
134134
}
135135

136136
// If there's not a custom converter specified via attribute, try for a default.
137137
converter = TypeDescriptor.GetConverter(value.GetType());
138138
if (converter.CanConvertTo(destinationType))
139139
{
140-
return converter.ConvertTo(value, destinationType);
140+
return converter.ConvertTo(null, CultureInfo.InvariantCulture, value, destinationType);
141141
}
142142

143143
// Try explicit opposite conversion.
144144
converter = TypeDescriptor.GetConverter(destinationType);
145145
if (converter.CanConvertFrom(value.GetType()))
146146
{
147-
return converter.ConvertFrom(value);
147+
return converter.ConvertFrom(null, CultureInfo.InvariantCulture, value);
148148
}
149149

150150
// Try a TryParse method.

‎test/Autofac.Configuration.Test/Core/ConfigurationExtensions_EnumerableParametersFixture.cs‎

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System.Collections;
22
using System.Collections.Generic;
3+
using System.Globalization;
34
using System.Linq;
45
using Xunit;
56

@@ -37,8 +38,8 @@ public void ConvertsTypeInList()
3738
var poco = container.Resolve<B>();
3839

3940
Assert.True(poco.List.Count == 2);
40-
Assert.Equal(1, poco.List[0]);
41-
Assert.Equal(2, poco.List[1]);
41+
Assert.Equal(1.234, poco.List[0]);
42+
Assert.Equal(2.345, poco.List[1]);
4243
}
4344

4445
public class C
@@ -54,8 +55,8 @@ public void FillsNonGenericListWithString()
5455
var poco = container.Resolve<C>();
5556

5657
Assert.True(poco.List.Count == 2);
57-
Assert.Equal("1", poco.List[0]);
58-
Assert.Equal("2", poco.List[1]);
58+
Assert.Equal("1.234", poco.List[0]);
59+
Assert.Equal("2.345", poco.List[1]);
5960
}
6061

6162
public class D
@@ -70,7 +71,7 @@ public void InjectsSingleValueWithConversion()
7071

7172
var poco = container.Resolve<D>();
7273

73-
Assert.True(poco.Num == 123);
74+
Assert.Equal(123.456, poco.Num);
7475
}
7576

7677
public class E
@@ -91,8 +92,28 @@ public void InjectsConstructorParameter()
9192
var poco = container.Resolve<E>();
9293

9394
Assert.True(poco.List.Count == 2);
94-
Assert.Equal(1, poco.List[0]);
95-
Assert.Equal(2, poco.List[1]);
95+
Assert.Equal(1.234, poco.List[0]);
96+
Assert.Equal(2.345, poco.List[1]);
97+
}
98+
99+
[Theory]
100+
[MemberData(nameof(ParsingCultures))]
101+
public void TypeConversionsAreCaseInvariant(CultureInfo culture)
102+
{
103+
// Issue #26 - parsing needs to be InvariantCulture or config fails
104+
// when it's moved from machine to machine.
105+
TestCulture.With(
106+
culture,
107+
() =>
108+
{
109+
var container = EmbeddedConfiguration.ConfigureContainerWithXml("ConfigurationExtensions_EnumerableParameters.xml").Build();
110+
111+
var poco = container.Resolve<E>();
112+
113+
Assert.True(poco.List.Count == 2);
114+
Assert.Equal(1.234, poco.List[0]);
115+
Assert.Equal(2.345, poco.List[1]);
116+
});
96117
}
97118

98119
public class G
@@ -129,8 +150,8 @@ public void InjectsGenericIEnumerable()
129150
Assert.NotNull(poco.Enumerable);
130151
var enumerable = poco.Enumerable.ToList();
131152
Assert.True(enumerable.Count == 2);
132-
Assert.Equal(1, enumerable[0]);
133-
Assert.Equal(2, enumerable[1]);
153+
Assert.Equal(1.234, enumerable[0]);
154+
Assert.Equal(2.345, enumerable[1]);
134155
}
135156

136157
public class I
@@ -147,8 +168,8 @@ public void InjectsGenericCollection()
147168

148169
Assert.NotNull(poco.Collection);
149170
Assert.True(poco.Collection.Count == 2);
150-
Assert.Equal(1, poco.Collection.First());
151-
Assert.Equal(2, poco.Collection.Last());
171+
Assert.Equal(1.234, poco.Collection.First());
172+
Assert.Equal(2.345, poco.Collection.Last());
152173
}
153174

154175
public class J
@@ -243,5 +264,13 @@ public void ParameterStringListInjectionSecondElementHasNoName()
243264
// Val2 is dropped from the configuration when it's parsed.
244265
Assert.Collection(poco.List, v => Assert.Equal("Val1", v));
245266
}
267+
268+
public static IEnumerable<object[]> ParsingCultures()
269+
{
270+
yield return new object[] { new CultureInfo("en-US") };
271+
yield return new object[] { new CultureInfo("es-MX") };
272+
yield return new object[] { new CultureInfo("it-IT") };
273+
yield return new object[] { CultureInfo.InvariantCulture };
274+
}
246275
}
247276
}
Lines changed: 96 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1,96 +1,96 @@
1-
<?xml version="1.0" encoding="utf-8" ?>
2-
<autofac defaultAssembly="Autofac.Configuration.Test">
3-
<components name="0">
4-
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+A</type>
5-
<properties>
6-
<List name="0">Val1</List>
7-
<List name="1">Val2</List>
8-
</properties>
9-
</components>
10-
<components name="1">
11-
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+B</type>
12-
<properties>
13-
<List name="0">1</List>
14-
<List name="1">2</List>
15-
</properties>
16-
</components>
17-
<components name="2">
18-
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+C</type>
19-
<properties>
20-
<List name="0">1</List>
21-
<List name="1">2</List>
22-
</properties>
23-
</components>
24-
<components name="3">
25-
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+D</type>
26-
<properties>
27-
<Num>123</Num>
28-
</properties>
29-
</components>
30-
<components name="4">
31-
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+E</type>
32-
<parameters>
33-
<List name="0">1</List>
34-
<List name="1">2</List>
35-
</parameters>
36-
</components>
37-
<!--
38-
Microsoft.Extensions.Configuration ignores empty elements so you
39-
don't know the difference between null and empty.
40-
<components name="5">
41-
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+F</type>
42-
<properties>
43-
<List />
44-
</properties>
45-
</components>
46-
-->
47-
<components name="6">
48-
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+G</type>
49-
<properties>
50-
<Enumerable name="0">Val1</Enumerable>
51-
<Enumerable name="1">Val2</Enumerable>
52-
</properties>
53-
</components>
54-
<components name="7">
55-
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+H</type>
56-
<properties>
57-
<Enumerable name="0">1</Enumerable>
58-
<Enumerable name="1">2</Enumerable>
59-
</properties>
60-
</components>
61-
<components name="8">
62-
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+I</type>
63-
<properties>
64-
<Collection name="0">1</Collection>
65-
<Collection name="1">2</Collection>
66-
</properties>
67-
</components>
68-
<components name="9">
69-
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+J</type>
70-
<parameters>
71-
<list name="0">Val1</list>
72-
<list name="1">Val2</list>
73-
</parameters>
74-
</components>
75-
<components name="10">
76-
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+K</type>
77-
<parameters>
78-
<list name="0">Val1</list>
79-
<list name="1">Val2</list>
80-
</parameters>
81-
</components>
82-
<components name="11">
83-
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+L</type>
84-
<parameters>
85-
<list name="0">Val1</list>
86-
<list name="1">Val2</list>
87-
</parameters>
88-
</components>
89-
<components name="12">
90-
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+M</type>
91-
<parameters>
92-
<list name="0">Val1</list>
93-
<list>Val2</list> <!-- no name -->
94-
</parameters>
95-
</components>
96-
</autofac>
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<autofac defaultAssembly="Autofac.Configuration.Test">
3+
<components name="0">
4+
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+A</type>
5+
<properties>
6+
<List name="0">Val1</List>
7+
<List name="1">Val2</List>
8+
</properties>
9+
</components>
10+
<components name="1">
11+
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+B</type>
12+
<properties>
13+
<List name="0">1.234</List>
14+
<List name="1">2.345</List>
15+
</properties>
16+
</components>
17+
<components name="2">
18+
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+C</type>
19+
<properties>
20+
<List name="0">1.234</List>
21+
<List name="1">2.345</List>
22+
</properties>
23+
</components>
24+
<components name="3">
25+
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+D</type>
26+
<properties>
27+
<Num>123.456</Num>
28+
</properties>
29+
</components>
30+
<components name="4">
31+
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+E</type>
32+
<parameters>
33+
<List name="0">1.234</List>
34+
<List name="1">2.345</List>
35+
</parameters>
36+
</components>
37+
<!--
38+
Microsoft.Extensions.Configuration ignores empty elements so you
39+
don't know the difference between null and empty.
40+
<components name="5">
41+
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+F</type>
42+
<properties>
43+
<List />
44+
</properties>
45+
</components>
46+
-->
47+
<components name="6">
48+
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+G</type>
49+
<properties>
50+
<Enumerable name="0">Val1</Enumerable>
51+
<Enumerable name="1">Val2</Enumerable>
52+
</properties>
53+
</components>
54+
<components name="7">
55+
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+H</type>
56+
<properties>
57+
<Enumerable name="0">1.234</Enumerable>
58+
<Enumerable name="1">2.345</Enumerable>
59+
</properties>
60+
</components>
61+
<components name="8">
62+
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+I</type>
63+
<properties>
64+
<Collection name="0">1.234</Collection>
65+
<Collection name="1">2.345</Collection>
66+
</properties>
67+
</components>
68+
<components name="9">
69+
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+J</type>
70+
<parameters>
71+
<list name="0">Val1</list>
72+
<list name="1">Val2</list>
73+
</parameters>
74+
</components>
75+
<components name="10">
76+
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+K</type>
77+
<parameters>
78+
<list name="0">Val1</list>
79+
<list name="1">Val2</list>
80+
</parameters>
81+
</components>
82+
<components name="11">
83+
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+L</type>
84+
<parameters>
85+
<list name="0">Val1</list>
86+
<list name="1">Val2</list>
87+
</parameters>
88+
</components>
89+
<components name="12">
90+
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+M</type>
91+
<parameters>
92+
<list name="0">Val1</list>
93+
<list>Val2</list> <!-- no name -->
94+
</parameters>
95+
</components>
96+
</autofac>
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System;
2+
using System.Globalization;
3+
using System.Threading;
4+
using Xunit;
5+
6+
namespace Autofac.Configuration.Test
7+
{
8+
public static class TestCulture
9+
{
10+
public static void With(CultureInfo culture, Action test)
11+
{
12+
var originalCulture = Thread.CurrentThread.CurrentCulture;
13+
var originalUICulture = Thread.CurrentThread.CurrentUICulture;
14+
Thread.CurrentThread.CurrentCulture = culture;
15+
Thread.CurrentThread.CurrentUICulture = culture;
16+
CultureInfo.CurrentCulture.ClearCachedData();
17+
CultureInfo.CurrentUICulture.ClearCachedData();
18+
try
19+
{
20+
test();
21+
}
22+
finally
23+
{
24+
Thread.CurrentThread.CurrentCulture = originalCulture;
25+
Thread.CurrentThread.CurrentUICulture = originalUICulture;
26+
CultureInfo.CurrentCulture.ClearCachedData();
27+
CultureInfo.CurrentUICulture.ClearCachedData();
28+
}
29+
}
30+
}
31+
}

‎test/Autofac.Configuration.Test/Util/TypeManipulationFixture.cs‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.ComponentModel;
34
using System.Globalization;
45
using System.Linq;
@@ -59,6 +60,27 @@ public void ChangeToCompatibleType_NoConversionNeeded()
5960
Assert.Equal(15, actual);
6061
}
6162

63+
[Theory]
64+
[MemberData(nameof(ParsingCultures))]
65+
public void ChangeToCompatibleType_UsesInvariantCulture(CultureInfo culture)
66+
{
67+
TestCulture.With(
68+
culture,
69+
() =>
70+
{
71+
var actual = TypeManipulation.ChangeToCompatibleType("123.456", typeof(double));
72+
Assert.Equal(123.456, actual);
73+
});
74+
}
75+
76+
public static IEnumerable<object[]> ParsingCultures()
77+
{
78+
yield return new object[] { new CultureInfo("en-US") };
79+
yield return new object[] { new CultureInfo("es-MX") };
80+
yield return new object[] { new CultureInfo("it-IT") };
81+
yield return new object[] { CultureInfo.InvariantCulture };
82+
}
83+
6284
public class Convertible
6385
{
6486
public int Value { get; set; }

0 commit comments

Comments
 (0)