summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Xamarin.Forms.Build.Tasks/CreateObjectVisitor.cs410
-rw-r--r--Xamarin.Forms.Build.Tasks/NodeILExtensions.cs72
-rw-r--r--Xamarin.Forms.Xaml.UnitTests/SetValue.xaml1
-rw-r--r--Xamarin.Forms.Xaml.UnitTests/SetValue.xaml.cs28
-rw-r--r--Xamarin.Forms.Xaml.UnitTests/X2009Primitives.xaml4
-rw-r--r--Xamarin.Forms.Xaml.UnitTests/X2009Primitives.xaml.cs69
-rw-r--r--Xamarin.Forms.Xaml/CreateValuesVisitor.cs108
-rw-r--r--Xamarin.Forms.Xaml/TypeConversionExtensions.cs34
8 files changed, 446 insertions, 280 deletions
diff --git a/Xamarin.Forms.Build.Tasks/CreateObjectVisitor.cs b/Xamarin.Forms.Build.Tasks/CreateObjectVisitor.cs
index 33a9a7f5..6d6405e1 100644
--- a/Xamarin.Forms.Build.Tasks/CreateObjectVisitor.cs
+++ b/Xamarin.Forms.Build.Tasks/CreateObjectVisitor.cs
@@ -317,18 +317,22 @@ namespace Xamarin.Forms.Build.Tasks
if (node.NamespaceURI != "clr-namespace:System;assembly=mscorlib")
return false;
var name = node.XmlType.Name.Split(':')[1];
- if (name == "Boolean" ||
- name == "String" ||
- name == "Char" ||
- name == "Decimal" ||
- name == "Single" ||
- name == "Double" ||
- name == "Byte" ||
- name == "Int16" ||
- name == "Int32" ||
- name == "Int64" ||
- name == "TimeSpan" ||
- name == "Uri")
+ if (name == "SByte" ||
+ name == "Int16" ||
+ name == "Int32" ||
+ name == "Int64" ||
+ name == "Byte" ||
+ name == "UInt16" ||
+ name == "UInt32" ||
+ name == "UInt64" ||
+ name == "Single" ||
+ name == "Double" ||
+ name == "Boolean" ||
+ name == "String" ||
+ name == "Char" ||
+ name == "Decimal" ||
+ name == "TimeSpan" ||
+ name == "Uri")
return true;
return false;
}
@@ -338,190 +342,206 @@ namespace Xamarin.Forms.Build.Tasks
var hasValue = node.CollectionItems.Count == 1 && node.CollectionItems[0] is ValueNode &&
((ValueNode)node.CollectionItems[0]).Value is string;
var valueString = hasValue ? ((ValueNode)node.CollectionItems[0]).Value as string : string.Empty;
- switch (typedef.FullName)
- {
- case "System.Boolean":
- bool outbool;
- if (hasValue && bool.TryParse(valueString, out outbool))
- yield return Instruction.Create(outbool ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
- else
- yield return Instruction.Create(OpCodes.Ldc_I4_0);
- break;
- case "System.String":
+ switch (typedef.FullName) {
+ case "System.SByte":
+ sbyte outsbyte;
+ if (hasValue && sbyte.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out outsbyte))
+ yield return Instruction.Create(OpCodes.Ldc_I4, (int)outsbyte);
+ else
+ yield return Instruction.Create(OpCodes.Ldc_I4, 0x00);
+ break;
+ case "System.Int16":
+ short outshort;
+ if (hasValue && short.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out outshort))
+ yield return Instruction.Create(OpCodes.Ldc_I4, outshort);
+ else
+ yield return Instruction.Create(OpCodes.Ldc_I4, 0x00);
+ break;
+ case "System.Int32":
+ int outint;
+ if (hasValue && int.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out outint))
+ yield return Instruction.Create(OpCodes.Ldc_I4, outint);
+ else
+ yield return Instruction.Create(OpCodes.Ldc_I4, 0x00);
+ break;
+ case "System.Int64":
+ long outlong;
+ if (hasValue && long.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out outlong))
+ yield return Instruction.Create(OpCodes.Ldc_I8, outlong);
+ else
+ yield return Instruction.Create(OpCodes.Ldc_I8, 0L);
+ break;
+ case "System.Byte":
+ byte outbyte;
+ if (hasValue && byte.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out outbyte))
+ yield return Instruction.Create(OpCodes.Ldc_I4, (int)outbyte);
+ else
+ yield return Instruction.Create(OpCodes.Ldc_I4, 0x00);
+ break;
+ case "System.UInt16":
+ short outushort;
+ if (hasValue && short.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out outushort))
+ yield return Instruction.Create(OpCodes.Ldc_I4, outushort);
+ else
+ yield return Instruction.Create(OpCodes.Ldc_I4, 0x00);
+ break;
+ case "System.UInt32":
+ int outuint;
+ if (hasValue && int.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out outuint))
+ yield return Instruction.Create(OpCodes.Ldc_I4, outuint);
+ else
+ yield return Instruction.Create(OpCodes.Ldc_I4, 0x00);
+ break;
+ case "System.UInt64":
+ long outulong;
+ if (hasValue && long.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out outulong))
+ yield return Instruction.Create(OpCodes.Ldc_I8, outulong);
+ else
+ yield return Instruction.Create(OpCodes.Ldc_I8, 0L);
+ break;
+ case "System.Boolean":
+ bool outbool;
+ if (hasValue && bool.TryParse(valueString, out outbool))
+ yield return Instruction.Create(outbool ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
+ else
+ yield return Instruction.Create(OpCodes.Ldc_I4_0);
+ break;
+ case "System.String":
+ yield return Instruction.Create(OpCodes.Ldstr, valueString);
+ break;
+ case "System.Object":
+ var ctorinfo =
+ Context.Body.Method.Module.TypeSystem.Object.Resolve()
+ .Methods.FirstOrDefault(md => md.IsConstructor && !md.HasParameters);
+ var ctor = Context.Body.Method.Module.Import(ctorinfo);
+ yield return Instruction.Create(OpCodes.Newobj, ctor);
+ break;
+ case "System.Char":
+ char outchar;
+ if (hasValue && char.TryParse(valueString, out outchar))
+ yield return Instruction.Create(OpCodes.Ldc_I4, outchar);
+ else
+ yield return Instruction.Create(OpCodes.Ldc_I4, 0x00);
+ break;
+ case "System.Decimal":
+ decimal outdecimal;
+ if (hasValue && decimal.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out outdecimal)) {
+ var vardef = new VariableDefinition(Context.Body.Method.Module.Import(typeof(decimal)));
+ Context.Body.Variables.Add(vardef);
+ //Use an extra temp var so we can push the value to the stack, just like other cases
+ // IL_0003: ldstr "adecimal"
+ // IL_0008: ldc.i4.s 0x6f
+ // IL_000a: call class [mscorlib]System.Globalization.CultureInfo class [mscorlib]System.Globalization.CultureInfo::get_InvariantCulture()
+ // IL_000f: ldloca.s 0
+ // IL_0011: call bool valuetype [mscorlib]System.Decimal::TryParse(string, valuetype [mscorlib]System.Globalization.NumberStyles, class [mscorlib]System.IFormatProvider, [out] valuetype [mscorlib]System.Decimal&)
+ // IL_0016: pop
yield return Instruction.Create(OpCodes.Ldstr, valueString);
- break;
- case "System.Object":
- var ctorinfo =
- Context.Body.Method.Module.TypeSystem.Object.Resolve()
- .Methods.FirstOrDefault(md => md.IsConstructor && !md.HasParameters);
- var ctor = Context.Body.Method.Module.Import(ctorinfo);
- yield return Instruction.Create(OpCodes.Newobj, ctor);
- break;
- case "System.Char":
- char outchar;
- if (hasValue && char.TryParse(valueString, out outchar))
- yield return Instruction.Create(OpCodes.Ldc_I4, outchar);
- else
- yield return Instruction.Create(OpCodes.Ldc_I4, 0x00);
- break;
- case "System.Decimal":
- decimal outdecimal;
- if (hasValue && decimal.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out outdecimal))
- {
- var vardef = new VariableDefinition(Context.Body.Method.Module.Import(typeof (decimal)));
- Context.Body.Variables.Add(vardef);
- //Use an extra temp var so we can push the value to the stack, just like other cases
- // IL_0003: ldstr "adecimal"
- // IL_0008: ldc.i4.s 0x6f
- // IL_000a: call class [mscorlib]System.Globalization.CultureInfo class [mscorlib]System.Globalization.CultureInfo::get_InvariantCulture()
- // IL_000f: ldloca.s 0
- // IL_0011: call bool valuetype [mscorlib]System.Decimal::TryParse(string, valuetype [mscorlib]System.Globalization.NumberStyles, class [mscorlib]System.IFormatProvider, [out] valuetype [mscorlib]System.Decimal&)
- // IL_0016: pop
- yield return Instruction.Create(OpCodes.Ldstr, valueString);
- yield return Instruction.Create(OpCodes.Ldc_I4, 0x6f); //NumberStyles.Number
- var getInvariantInfo =
- Context.Body.Method.Module.Import(typeof (CultureInfo))
- .Resolve()
- .Properties.FirstOrDefault(pd => pd.Name == "InvariantCulture")
- .GetMethod;
- var getInvariant = Context.Body.Method.Module.Import(getInvariantInfo);
- yield return Instruction.Create(OpCodes.Call, getInvariant);
- yield return Instruction.Create(OpCodes.Ldloca, vardef);
- var tryParseInfo =
- Context.Body.Method.Module.Import(typeof (decimal))
- .Resolve()
- .Methods.FirstOrDefault(md => md.Name == "TryParse" && md.Parameters.Count == 4);
- var tryParse = Context.Body.Method.Module.Import(tryParseInfo);
- yield return Instruction.Create(OpCodes.Call, tryParse);
- yield return Instruction.Create(OpCodes.Pop);
- yield return Instruction.Create(OpCodes.Ldloc, vardef);
- }
- else
- {
- yield return Instruction.Create(OpCodes.Ldc_I4_0);
- var decimalctorinfo =
- Context.Body.Method.Module.Import(typeof (decimal))
- .Resolve()
- .Methods.FirstOrDefault(
- md => md.IsConstructor && md.Parameters.Count == 1 && md.Parameters[0].ParameterType.FullName == "System.Int32");
- var decimalctor = Context.Body.Method.Module.Import(decimalctorinfo);
- yield return Instruction.Create(OpCodes.Newobj, decimalctor);
- }
- break;
- case "System.Single":
- float outfloat;
- if (hasValue && float.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out outfloat))
- yield return Instruction.Create(OpCodes.Ldc_R4, outfloat);
- else
- yield return Instruction.Create(OpCodes.Ldc_R4, 0f);
- break;
- case "System.Double":
- double outdouble;
- if (hasValue && double.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out outdouble))
- yield return Instruction.Create(OpCodes.Ldc_R8, outdouble);
- else
- yield return Instruction.Create(OpCodes.Ldc_R8, 0d);
- break;
- case "System.Byte":
- byte outbyte;
- if (hasValue && byte.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out outbyte))
- yield return Instruction.Create(OpCodes.Ldc_I4, (int)outbyte);
- else
- yield return Instruction.Create(OpCodes.Ldc_I4, 0x00);
- break;
- case "System.Int16":
- short outshort;
- if (hasValue && short.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out outshort))
- yield return Instruction.Create(OpCodes.Ldc_I4, outshort);
- else
- yield return Instruction.Create(OpCodes.Ldc_I4, 0x00);
- break;
- case "System.Int32":
- int outint;
- if (hasValue && int.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out outint))
- yield return Instruction.Create(OpCodes.Ldc_I4, outint);
- else
- yield return Instruction.Create(OpCodes.Ldc_I4, 0x00);
- break;
- case "System.Int64":
- long outlong;
- if (hasValue && long.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out outlong))
- yield return Instruction.Create(OpCodes.Ldc_I8, outlong);
- else
- yield return Instruction.Create(OpCodes.Ldc_I8, 0L);
- break;
- case "System.TimeSpan":
- TimeSpan outspan;
- if (hasValue && TimeSpan.TryParse(valueString, CultureInfo.InvariantCulture, out outspan))
- {
- var vardef = new VariableDefinition(Context.Body.Method.Module.Import(typeof (TimeSpan)));
- Context.Body.Variables.Add(vardef);
- //Use an extra temp var so we can push the value to the stack, just like other cases
- yield return Instruction.Create(OpCodes.Ldstr, valueString);
- var getInvariantInfo =
- Context.Body.Method.Module.Import(typeof (CultureInfo))
- .Resolve()
- .Properties.FirstOrDefault(pd => pd.Name == "InvariantCulture")
- .GetMethod;
- var getInvariant = Context.Body.Method.Module.Import(getInvariantInfo);
- yield return Instruction.Create(OpCodes.Call, getInvariant);
- yield return Instruction.Create(OpCodes.Ldloca, vardef);
- var tryParseInfo =
- Context.Body.Method.Module.Import(typeof (TimeSpan))
- .Resolve()
- .Methods.FirstOrDefault(md => md.Name == "TryParse" && md.Parameters.Count == 3);
- var tryParse = Context.Body.Method.Module.Import(tryParseInfo);
- yield return Instruction.Create(OpCodes.Call, tryParse);
- yield return Instruction.Create(OpCodes.Pop);
- yield return Instruction.Create(OpCodes.Ldloc, vardef);
- }
- else
- {
- yield return Instruction.Create(OpCodes.Ldc_I8, 0L);
- var timespanctorinfo =
- Context.Body.Method.Module.Import(typeof (TimeSpan))
- .Resolve()
- .Methods.FirstOrDefault(
- md => md.IsConstructor && md.Parameters.Count == 1 && md.Parameters[0].ParameterType.FullName == "System.Int64");
- var timespanctor = Context.Body.Method.Module.Import(timespanctorinfo);
- yield return Instruction.Create(OpCodes.Newobj, timespanctor);
- }
- break;
- case "System.Uri":
- Uri outuri;
- if (hasValue && Uri.TryCreate(valueString, UriKind.RelativeOrAbsolute, out outuri))
- {
- var vardef = new VariableDefinition(Context.Body.Method.Module.Import(typeof (Uri)));
- Context.Body.Variables.Add(vardef);
- //Use an extra temp var so we can push the value to the stack, just like other cases
- yield return Instruction.Create(OpCodes.Ldstr, valueString);
- yield return Instruction.Create(OpCodes.Ldc_I4, (int)UriKind.RelativeOrAbsolute);
- yield return Instruction.Create(OpCodes.Ldloca, vardef);
- var tryCreateInfo =
- Context.Body.Method.Module.Import(typeof (Uri))
- .Resolve()
- .Methods.FirstOrDefault(md => md.Name == "TryCreate" && md.Parameters.Count == 3);
- var tryCreate = Context.Body.Method.Module.Import(tryCreateInfo);
- yield return Instruction.Create(OpCodes.Call, tryCreate);
- yield return Instruction.Create(OpCodes.Pop);
- yield return Instruction.Create(OpCodes.Ldloc, vardef);
- }
- else
- yield return Instruction.Create(OpCodes.Ldnull);
- break;
- default:
- var defaultctorinfo = typedef.Methods.FirstOrDefault(md => md.IsConstructor && !md.HasParameters);
- if (defaultctorinfo != null)
- {
- var defaultctor = Context.Body.Method.Module.Import(defaultctorinfo);
- yield return Instruction.Create(OpCodes.Newobj, defaultctor);
- }
- else
- {
- //should never happen. but if it does, this prevents corrupting the IL stack
- yield return Instruction.Create(OpCodes.Ldnull);
- }
- break;
+ yield return Instruction.Create(OpCodes.Ldc_I4, 0x6f); //NumberStyles.Number
+ var getInvariantInfo =
+ Context.Body.Method.Module.Import(typeof(CultureInfo))
+ .Resolve()
+ .Properties.FirstOrDefault(pd => pd.Name == "InvariantCulture")
+ .GetMethod;
+ var getInvariant = Context.Body.Method.Module.Import(getInvariantInfo);
+ yield return Instruction.Create(OpCodes.Call, getInvariant);
+ yield return Instruction.Create(OpCodes.Ldloca, vardef);
+ var tryParseInfo =
+ Context.Body.Method.Module.Import(typeof(decimal))
+ .Resolve()
+ .Methods.FirstOrDefault(md => md.Name == "TryParse" && md.Parameters.Count == 4);
+ var tryParse = Context.Body.Method.Module.Import(tryParseInfo);
+ yield return Instruction.Create(OpCodes.Call, tryParse);
+ yield return Instruction.Create(OpCodes.Pop);
+ yield return Instruction.Create(OpCodes.Ldloc, vardef);
+ } else {
+ yield return Instruction.Create(OpCodes.Ldc_I4_0);
+ var decimalctorinfo =
+ Context.Body.Method.Module.Import(typeof(decimal))
+ .Resolve()
+ .Methods.FirstOrDefault(
+ md => md.IsConstructor && md.Parameters.Count == 1 && md.Parameters [0].ParameterType.FullName == "System.Int32");
+ var decimalctor = Context.Body.Method.Module.Import(decimalctorinfo);
+ yield return Instruction.Create(OpCodes.Newobj, decimalctor);
+ }
+ break;
+ case "System.Single":
+ float outfloat;
+ if (hasValue && float.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out outfloat))
+ yield return Instruction.Create(OpCodes.Ldc_R4, outfloat);
+ else
+ yield return Instruction.Create(OpCodes.Ldc_R4, 0f);
+ break;
+ case "System.Double":
+ double outdouble;
+ if (hasValue && double.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out outdouble))
+ yield return Instruction.Create(OpCodes.Ldc_R8, outdouble);
+ else
+ yield return Instruction.Create(OpCodes.Ldc_R8, 0d);
+ break;
+ case "System.TimeSpan":
+ TimeSpan outspan;
+ if (hasValue && TimeSpan.TryParse(valueString, CultureInfo.InvariantCulture, out outspan)) {
+ var vardef = new VariableDefinition(Context.Body.Method.Module.Import(typeof(TimeSpan)));
+ Context.Body.Variables.Add(vardef);
+ //Use an extra temp var so we can push the value to the stack, just like other cases
+ yield return Instruction.Create(OpCodes.Ldstr, valueString);
+ var getInvariantInfo =
+ Context.Body.Method.Module.Import(typeof(CultureInfo))
+ .Resolve()
+ .Properties.FirstOrDefault(pd => pd.Name == "InvariantCulture")
+ .GetMethod;
+ var getInvariant = Context.Body.Method.Module.Import(getInvariantInfo);
+ yield return Instruction.Create(OpCodes.Call, getInvariant);
+ yield return Instruction.Create(OpCodes.Ldloca, vardef);
+ var tryParseInfo =
+ Context.Body.Method.Module.Import(typeof(TimeSpan))
+ .Resolve()
+ .Methods.FirstOrDefault(md => md.Name == "TryParse" && md.Parameters.Count == 3);
+ var tryParse = Context.Body.Method.Module.Import(tryParseInfo);
+ yield return Instruction.Create(OpCodes.Call, tryParse);
+ yield return Instruction.Create(OpCodes.Pop);
+ yield return Instruction.Create(OpCodes.Ldloc, vardef);
+ } else {
+ yield return Instruction.Create(OpCodes.Ldc_I8, 0L);
+ var timespanctorinfo =
+ Context.Body.Method.Module.Import(typeof(TimeSpan))
+ .Resolve()
+ .Methods.FirstOrDefault(
+ md => md.IsConstructor && md.Parameters.Count == 1 && md.Parameters [0].ParameterType.FullName == "System.Int64");
+ var timespanctor = Context.Body.Method.Module.Import(timespanctorinfo);
+ yield return Instruction.Create(OpCodes.Newobj, timespanctor);
+ }
+ break;
+ case "System.Uri":
+ Uri outuri;
+ if (hasValue && Uri.TryCreate(valueString, UriKind.RelativeOrAbsolute, out outuri)) {
+ var vardef = new VariableDefinition(Context.Body.Method.Module.Import(typeof(Uri)));
+ Context.Body.Variables.Add(vardef);
+ //Use an extra temp var so we can push the value to the stack, just like other cases
+ yield return Instruction.Create(OpCodes.Ldstr, valueString);
+ yield return Instruction.Create(OpCodes.Ldc_I4, (int)UriKind.RelativeOrAbsolute);
+ yield return Instruction.Create(OpCodes.Ldloca, vardef);
+ var tryCreateInfo =
+ Context.Body.Method.Module.Import(typeof(Uri))
+ .Resolve()
+ .Methods.FirstOrDefault(md => md.Name == "TryCreate" && md.Parameters.Count == 3);
+ var tryCreate = Context.Body.Method.Module.Import(tryCreateInfo);
+ yield return Instruction.Create(OpCodes.Call, tryCreate);
+ yield return Instruction.Create(OpCodes.Pop);
+ yield return Instruction.Create(OpCodes.Ldloc, vardef);
+ } else
+ yield return Instruction.Create(OpCodes.Ldnull);
+ break;
+ default:
+ var defaultctorinfo = typedef.Methods.FirstOrDefault(md => md.IsConstructor && !md.HasParameters);
+ if (defaultctorinfo != null) {
+ var defaultctor = Context.Body.Method.Module.Import(defaultctorinfo);
+ yield return Instruction.Create(OpCodes.Newobj, defaultctor);
+ } else {
+ //should never happen. but if it does, this prevents corrupting the IL stack
+ yield return Instruction.Create(OpCodes.Ldnull);
+ }
+ break;
}
}
}
diff --git a/Xamarin.Forms.Build.Tasks/NodeILExtensions.cs b/Xamarin.Forms.Build.Tasks/NodeILExtensions.cs
index a7fed895..31c1a1a8 100644
--- a/Xamarin.Forms.Build.Tasks/NodeILExtensions.cs
+++ b/Xamarin.Forms.Build.Tasks/NodeILExtensions.cs
@@ -114,58 +114,100 @@ namespace Xamarin.Forms.Build.Tasks
yield return Instruction.Create(OpCodes.Ldc_I4, ParseEnum(targetTypeRef, str, node));
else if (targetTypeRef.FullName == "System.Char")
yield return Instruction.Create(OpCodes.Ldc_I4, Char.Parse(str));
- else if (targetTypeRef.FullName == "System.Byte")
- yield return Instruction.Create(OpCodes.Ldc_I4, Byte.Parse(str, CultureInfo.InvariantCulture));
+ else if (targetTypeRef.FullName == "System.SByte")
+ yield return Instruction.Create(OpCodes.Ldc_I4, SByte.Parse(str, CultureInfo.InvariantCulture));
else if (targetTypeRef.FullName == "System.Int16")
yield return Instruction.Create(OpCodes.Ldc_I4, Int16.Parse(str, CultureInfo.InvariantCulture));
else if (targetTypeRef.FullName == "System.Int32")
yield return Instruction.Create(OpCodes.Ldc_I4, Int32.Parse(str, CultureInfo.InvariantCulture));
else if (targetTypeRef.FullName == "System.Int64")
yield return Instruction.Create(OpCodes.Ldc_I8, Int64.Parse(str, CultureInfo.InvariantCulture));
+ else if (targetTypeRef.FullName == "System.Byte")
+ yield return Instruction.Create(OpCodes.Ldc_I4, Byte.Parse(str, CultureInfo.InvariantCulture));
+ else if (targetTypeRef.FullName == "System.UInt16")
+ yield return Instruction.Create(OpCodes.Ldc_I4, UInt16.Parse(str, CultureInfo.InvariantCulture));
+ else if (targetTypeRef.FullName == "System.UInt32")
+ yield return Instruction.Create(OpCodes.Ldc_I4, UInt32.Parse(str, CultureInfo.InvariantCulture));
+ else if (targetTypeRef.FullName == "System.UInt64")
+ yield return Instruction.Create(OpCodes.Ldc_I8, UInt64.Parse(str, CultureInfo.InvariantCulture));
else if (targetTypeRef.FullName == "System.Single")
yield return Instruction.Create(OpCodes.Ldc_R4, Single.Parse(str, CultureInfo.InvariantCulture));
else if (targetTypeRef.FullName == "System.Double")
yield return Instruction.Create(OpCodes.Ldc_R8, Double.Parse(str, CultureInfo.InvariantCulture));
- else if (targetTypeRef.FullName == "System.Boolean")
- {
+ else if (targetTypeRef.FullName == "System.Boolean") {
if (Boolean.Parse(str))
yield return Instruction.Create(OpCodes.Ldc_I4_1);
else
yield return Instruction.Create(OpCodes.Ldc_I4_0);
- }
- else if (targetTypeRef.FullName == "System.TimeSpan")
- {
+ } else if (targetTypeRef.FullName == "System.TimeSpan") {
var ts = TimeSpan.Parse(str, CultureInfo.InvariantCulture);
var ticks = ts.Ticks;
var timeSpanCtor =
- module.Import(typeof (TimeSpan))
+ module.Import(typeof(TimeSpan))
.Resolve()
.Methods.FirstOrDefault(md => md.IsConstructor && md.Parameters.Count == 1);
var timeSpanCtorRef = module.Import(timeSpanCtor);
yield return Instruction.Create(OpCodes.Ldc_I8, ticks);
yield return Instruction.Create(OpCodes.Newobj, timeSpanCtorRef);
- }
- else if (targetTypeRef.FullName == "System.DateTime")
- {
+ } else if (targetTypeRef.FullName == "System.DateTime") {
var dt = DateTime.Parse(str, CultureInfo.InvariantCulture);
var ticks = dt.Ticks;
var dateTimeCtor =
- module.Import(typeof (DateTime))
+ module.Import(typeof(DateTime))
.Resolve()
.Methods.FirstOrDefault(md => md.IsConstructor && md.Parameters.Count == 1);
var dateTimeCtorRef = module.Import(dateTimeCtor);
yield return Instruction.Create(OpCodes.Ldc_I8, ticks);
yield return Instruction.Create(OpCodes.Newobj, dateTimeCtorRef);
- }
- else if (targetTypeRef.FullName == "System.String" && str.StartsWith("{}", StringComparison.Ordinal))
+ } else if (targetTypeRef.FullName == "System.String" && str.StartsWith("{}", StringComparison.Ordinal))
yield return Instruction.Create(OpCodes.Ldstr, str.Substring(2));
else if (targetTypeRef.FullName == "System.String")
yield return Instruction.Create(OpCodes.Ldstr, str);
else if (targetTypeRef.FullName == "System.Object")
yield return Instruction.Create(OpCodes.Ldstr, str);
- else
+ else if (targetTypeRef.FullName == "System.Decimal") {
+ decimal outdecimal;
+ if (decimal.TryParse(str, NumberStyles.Number, CultureInfo.InvariantCulture, out outdecimal)) {
+ var vardef = new VariableDefinition(context.Body.Method.Module.Import(typeof(decimal)));
+ context.Body.Variables.Add(vardef);
+ //Use an extra temp var so we can push the value to the stack, just like other cases
+ // IL_0003: ldstr "adecimal"
+ // IL_0008: ldc.i4.s 0x6f
+ // IL_000a: call class [mscorlib]System.Globalization.CultureInfo class [mscorlib]System.Globalization.CultureInfo::get_InvariantCulture()
+ // IL_000f: ldloca.s 0
+ // IL_0011: call bool valuetype [mscorlib]System.Decimal::TryParse(string, valuetype [mscorlib]System.Globalization.NumberStyles, class [mscorlib]System.IFormatProvider, [out] valuetype [mscorlib]System.Decimal&)
+ // IL_0016: pop
+ yield return Instruction.Create(OpCodes.Ldstr, str);
+ yield return Instruction.Create(OpCodes.Ldc_I4, 0x6f); //NumberStyles.Number
+ var getInvariantInfo =
+ context.Body.Method.Module.Import(typeof(CultureInfo))
+ .Resolve()
+ .Properties.FirstOrDefault(pd => pd.Name == "InvariantCulture")
+ .GetMethod;
+ var getInvariant = context.Body.Method.Module.Import(getInvariantInfo);
+ yield return Instruction.Create(OpCodes.Call, getInvariant);
+ yield return Instruction.Create(OpCodes.Ldloca, vardef);
+ var tryParseInfo =
+ context.Body.Method.Module.Import(typeof(decimal))
+ .Resolve()
+ .Methods.FirstOrDefault(md => md.Name == "TryParse" && md.Parameters.Count == 4);
+ var tryParse = context.Body.Method.Module.Import(tryParseInfo);
+ yield return Instruction.Create(OpCodes.Call, tryParse);
+ yield return Instruction.Create(OpCodes.Pop);
+ yield return Instruction.Create(OpCodes.Ldloc, vardef);
+ } else {
+ yield return Instruction.Create(OpCodes.Ldc_I4_0);
+ var decimalctorinfo =
+ context.Body.Method.Module.Import(typeof(decimal))
+ .Resolve()
+ .Methods.FirstOrDefault(
+ md => md.IsConstructor && md.Parameters.Count == 1 && md.Parameters [0].ParameterType.FullName == "System.Int32");
+ var decimalctor = context.Body.Method.Module.Import(decimalctorinfo);
+ yield return Instruction.Create(OpCodes.Newobj, decimalctor);
+ }
+ } else
yield return Instruction.Create(OpCodes.Ldnull);
if (isNullable)
diff --git a/Xamarin.Forms.Xaml.UnitTests/SetValue.xaml b/Xamarin.Forms.Xaml.UnitTests/SetValue.xaml
index da844ed0..75784273 100644
--- a/Xamarin.Forms.Xaml.UnitTests/SetValue.xaml
+++ b/Xamarin.Forms.Xaml.UnitTests/SetValue.xaml
@@ -83,5 +83,6 @@
<d:IgnorableElement />
</ContentView.Content>
</ContentView>
+ <local:MockViewWithValues x:Name="mockView0" UShort="32" ADecimal="42" />
</StackLayout>
</ContentPage> \ No newline at end of file
diff --git a/Xamarin.Forms.Xaml.UnitTests/SetValue.xaml.cs b/Xamarin.Forms.Xaml.UnitTests/SetValue.xaml.cs
index 2226402c..3343ed7a 100644
--- a/Xamarin.Forms.Xaml.UnitTests/SetValue.xaml.cs
+++ b/Xamarin.Forms.Xaml.UnitTests/SetValue.xaml.cs
@@ -2,6 +2,7 @@
using System.Linq;
using NUnit.Framework;
+using Xamarin.Forms.Core.UnitTests;
namespace Xamarin.Forms.Xaml.UnitTests
{
@@ -13,6 +14,12 @@ namespace Xamarin.Forms.Xaml.UnitTests
}
}
+ public class MockViewWithValues : View
+ {
+ public UInt16 UShort { get; set; }
+ public decimal ADecimal { get; set; }
+ }
+
public partial class SetValue : ContentPage
{
public SetValue ()
@@ -34,6 +41,18 @@ namespace Xamarin.Forms.Xaml.UnitTests
[TestFixture]
public class Tests
{
+ [SetUp]
+ public void Setup()
+ {
+ Device.PlatformServices = new MockPlatformServices();
+ }
+
+ [TearDown]
+ public void TearDown()
+ {
+ Device.PlatformServices = null;
+ }
+
[TestCase (false)]
[TestCase (true)]
public void SetValueToBP (bool useCompiledXaml)
@@ -215,6 +234,15 @@ namespace Xamarin.Forms.Xaml.UnitTests
var page = new SetValue(useCompiledXaml);
Assert.That(page.contentview2.Content, Is.TypeOf<Label>());
}
+
+ [TestCase(false)]
+ [TestCase(true)]
+ public void MorePrimitiveTypes(bool useCompiledXaml)
+ {
+ var page = new SetValue(useCompiledXaml);
+ Assert.AreEqual((ushort)32, page.mockView0.UShort);
+ Assert.AreEqual((decimal)42, page.mockView0.ADecimal);
+ }
}
}
} \ No newline at end of file
diff --git a/Xamarin.Forms.Xaml.UnitTests/X2009Primitives.xaml b/Xamarin.Forms.Xaml.UnitTests/X2009Primitives.xaml
index a7a91edc..c9efad23 100644
--- a/Xamarin.Forms.Xaml.UnitTests/X2009Primitives.xaml
+++ b/Xamarin.Forms.Xaml.UnitTests/X2009Primitives.xaml
@@ -37,6 +37,10 @@
<x:TimeSpan x:Key="defaultTimeSpan"/>
<x:Uri x:Key="anUri">http://xamarin.com/forms</x:Uri>
<x:Uri x:Key="defaultUri"/>
+ <x:SByte x:Key="aSByte">42</x:SByte>
+ <x:UInt16 x:Key="aUInt16">43</x:UInt16>
+ <x:UInt32 x:Key="aUInt32">44</x:UInt32>
+ <x:UInt64 x:Key="aUInt64">45</x:UInt64>
</ResourceDictionary>
</ContentPage.Resources>
</ContentPage> \ No newline at end of file
diff --git a/Xamarin.Forms.Xaml.UnitTests/X2009Primitives.xaml.cs b/Xamarin.Forms.Xaml.UnitTests/X2009Primitives.xaml.cs
index 60ead7ca..d7ef6eac 100644
--- a/Xamarin.Forms.Xaml.UnitTests/X2009Primitives.xaml.cs
+++ b/Xamarin.Forms.Xaml.UnitTests/X2009Primitives.xaml.cs
@@ -4,6 +4,7 @@ using System.Collections.Generic;
using NUnit.Framework;
using Xamarin.Forms;
+using Xamarin.Forms.Core.UnitTests;
namespace Xamarin.Forms.Xaml.UnitTests
{
@@ -22,6 +23,18 @@ namespace Xamarin.Forms.Xaml.UnitTests
[TestFixture]
public class Tests
{
+ [SetUp]
+ public void Setup()
+ {
+ Device.PlatformServices = new MockPlatformServices();
+ }
+
+ [TearDown]
+ public void TearDown()
+ {
+ Device.PlatformServices = null;
+ }
+
[TestCase (false)]
[TestCase (true)]
public void SupportsXString (bool useCompiledXaml)
@@ -144,11 +157,17 @@ namespace Xamarin.Forms.Xaml.UnitTests
Assert.That (defaultDouble, Is.TypeOf<double> ());
Assert.AreEqual (default(double), (double)defaultDouble, .0001d);
- Assert.True (layout.Resources.ContainsKey ("aByte"));
+ Assert.True(layout.Resources.ContainsKey("aByte"));
var aByte = layout.Resources ["aByte"];
- Assert.NotNull (aByte);
- Assert.That (aByte, Is.TypeOf<byte> ());
- Assert.AreEqual (54, (byte)aByte);
+ Assert.NotNull(aByte);
+ Assert.That(aByte, Is.TypeOf<byte>());
+ Assert.AreEqual(54, (byte)aByte);
+
+ Assert.True(layout.Resources.ContainsKey("aSByte"));
+ var aSByte = layout.Resources ["aSByte"];
+ Assert.NotNull(aSByte);
+ Assert.That(aSByte, Is.TypeOf<sbyte>());
+ Assert.AreEqual(42, (sbyte)aSByte);
Assert.True (layout.Resources.ContainsKey ("defaultByte"));
var defaultByte = layout.Resources ["defaultByte"];
@@ -156,11 +175,17 @@ namespace Xamarin.Forms.Xaml.UnitTests
Assert.That (defaultByte, Is.TypeOf<byte> ());
Assert.AreEqual (default(byte), (byte)defaultByte);
- Assert.True (layout.Resources.ContainsKey ("anInt16"));
+ Assert.True(layout.Resources.ContainsKey("anInt16"));
var anInt16 = layout.Resources ["anInt16"];
- Assert.NotNull (anInt16);
- Assert.That (anInt16, Is.TypeOf<short> ());
- Assert.AreEqual (43, (short)anInt16);
+ Assert.NotNull(anInt16);
+ Assert.That(anInt16, Is.TypeOf<short>());
+ Assert.AreEqual(43, (short)anInt16);
+
+ Assert.True(layout.Resources.ContainsKey("aUInt16"));
+ var aUInt16 = layout.Resources ["aUInt16"];
+ Assert.NotNull(aUInt16);
+ Assert.That(aUInt16, Is.TypeOf<ushort>());
+ Assert.AreEqual(43, (ushort)aUInt16);
Assert.True (layout.Resources.ContainsKey ("defaultInt16"));
var defaultInt16 = layout.Resources ["defaultInt16"];
@@ -168,11 +193,17 @@ namespace Xamarin.Forms.Xaml.UnitTests
Assert.That (defaultInt16, Is.TypeOf<short> ());
Assert.AreEqual (default(short), (short)defaultInt16);
- Assert.True (layout.Resources.ContainsKey ("anInt32"));
+ Assert.True(layout.Resources.ContainsKey("anInt32"));
var anInt32 = layout.Resources ["anInt32"];
- Assert.NotNull (anInt32);
- Assert.That (anInt32, Is.TypeOf<int> ());
- Assert.AreEqual (44, (int)anInt32);
+ Assert.NotNull(anInt32);
+ Assert.That(anInt32, Is.TypeOf<int>());
+ Assert.AreEqual(44, (int)anInt32);
+
+ Assert.True(layout.Resources.ContainsKey("aUInt32"));
+ var aUInt32 = layout.Resources ["aUInt32"];
+ Assert.NotNull(aUInt32);
+ Assert.That(aUInt32, Is.TypeOf<uint>());
+ Assert.AreEqual(44, (uint)aUInt32);
Assert.True (layout.Resources.ContainsKey ("defaultInt32"));
var defaultInt32 = layout.Resources ["defaultInt32"];
@@ -180,11 +211,17 @@ namespace Xamarin.Forms.Xaml.UnitTests
Assert.That (defaultInt32, Is.TypeOf<int> ());
Assert.AreEqual (default(int), (int)defaultInt32);
- Assert.True (layout.Resources.ContainsKey ("anInt64"));
+ Assert.True(layout.Resources.ContainsKey("anInt64"));
var anInt64 = layout.Resources ["anInt64"];
- Assert.NotNull (anInt64);
- Assert.That (anInt64, Is.TypeOf<long> ());
- Assert.AreEqual (45, (long)anInt64);
+ Assert.NotNull(anInt64);
+ Assert.That(anInt64, Is.TypeOf<long>());
+ Assert.AreEqual(45, (long)anInt64);
+
+ Assert.True(layout.Resources.ContainsKey("aUInt64"));
+ var aUInt64 = layout.Resources ["aUInt64"];
+ Assert.NotNull(aUInt64);
+ Assert.That(aUInt64, Is.TypeOf<ulong>());
+ Assert.AreEqual(45, (ulong)aUInt64);
Assert.True (layout.Resources.ContainsKey ("defaultInt64"));
var defaultInt64 = layout.Resources ["defaultInt64"];
diff --git a/Xamarin.Forms.Xaml/CreateValuesVisitor.cs b/Xamarin.Forms.Xaml/CreateValuesVisitor.cs
index 25a936fa..c2331bf1 100644
--- a/Xamarin.Forms.Xaml/CreateValuesVisitor.cs
+++ b/Xamarin.Forms.Xaml/CreateValuesVisitor.cs
@@ -296,73 +296,87 @@ namespace Xamarin.Forms.Xaml
{
var valuestring = ((ValueNode)node.CollectionItems[0]).Value as string;
- if (nodeType == typeof (bool))
- {
- bool outbool;
- if (bool.TryParse(valuestring, out outbool))
- value = outbool;
+ if (nodeType == typeof(SByte)) {
+ sbyte retval;
+ if (sbyte.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
+ return retval;
}
- else if (nodeType == typeof (char))
- {
- char retval;
- if (char.TryParse(valuestring, out retval))
- value = retval;
+ if (nodeType == typeof(Int16)) {
+ short retval;
+ if (short.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
+ return retval;
}
- else if (nodeType == typeof (string))
- value = valuestring;
- else if (nodeType == typeof (decimal))
- {
- decimal retval;
- if (decimal.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
- value = retval;
+ if (nodeType == typeof(Int32)) {
+ int retval;
+ if (int.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
+ return retval;
}
- else if (nodeType == typeof (float))
- {
+ if (nodeType == typeof(Int64)) {
+ long retval;
+ if (long.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
+ return retval;
+ }
+ if (nodeType == typeof(Byte)) {
+ byte retval;
+ if (byte.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
+ return retval;
+ }
+ if (nodeType == typeof(UInt16)) {
+ ushort retval;
+ if (ushort.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
+ return retval;
+ }
+ if (nodeType == typeof(UInt32)) {
+ uint retval;
+ if (uint.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
+ return retval;
+ }
+ if (nodeType == typeof(UInt64)) {
+ ulong retval;
+ if (ulong.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
+ return retval;
+ }
+ if (nodeType == typeof(Single)) {
float retval;
if (float.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
- value = retval;
+ return retval;
}
- else if (nodeType == typeof (double))
- {
+ if (nodeType == typeof(Double)) {
double retval;
if (double.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
- value = retval;
- }
- else if (nodeType == typeof (byte))
- {
- byte retval;
- if (byte.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
- value = retval;
+ return retval;
}
- else if (nodeType == typeof (short))
+ if (nodeType == typeof (Boolean))
{
- short retval;
- if (short.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
- value = retval;
+ bool outbool;
+ if (bool.TryParse(valuestring, out outbool))
+ return outbool;
}
- else if (nodeType == typeof (int))
- {
- int retval;
- if (int.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
- value = retval;
+ if (nodeType == typeof(TimeSpan)) {
+ TimeSpan retval;
+ if (TimeSpan.TryParse(valuestring, CultureInfo.InvariantCulture, out retval))
+ return retval;
}
- else if (nodeType == typeof (long))
+ if (nodeType == typeof (char))
{
- long retval;
- if (long.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
- value = retval;
+ char retval;
+ if (char.TryParse(valuestring, out retval))
+ return retval;
}
- else if (nodeType == typeof (TimeSpan))
+ if (nodeType == typeof (string))
+ return valuestring;
+ if (nodeType == typeof (decimal))
{
- TimeSpan retval;
- if (TimeSpan.TryParse(valuestring, CultureInfo.InvariantCulture, out retval))
- value = retval;
+ decimal retval;
+ if (decimal.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
+ return retval;
}
+
else if (nodeType == typeof (Uri))
{
Uri retval;
if (Uri.TryCreate(valuestring, UriKind.RelativeOrAbsolute, out retval))
- value = retval;
+ return retval;
}
}
return value;
diff --git a/Xamarin.Forms.Xaml/TypeConversionExtensions.cs b/Xamarin.Forms.Xaml/TypeConversionExtensions.cs
index 7e377ea4..a29b3af2 100644
--- a/Xamarin.Forms.Xaml/TypeConversionExtensions.cs
+++ b/Xamarin.Forms.Xaml/TypeConversionExtensions.cs
@@ -130,23 +130,43 @@ namespace Xamarin.Forms.Xaml
//Obvious Built-in conversions
if (toType.GetTypeInfo().IsEnum)
return Enum.Parse(toType, str);
- //TODO supports Int16, 64, Byte, Char, ...
- if (toType == typeof (Int32))
+ if (toType == typeof(SByte))
+ return SByte.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof(Int16))
+ return Int16.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof(Int32))
return Int32.Parse(str, CultureInfo.InvariantCulture);
- if (toType == typeof (float))
+ if (toType == typeof(Int64))
+ return Int64.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof(Byte))
+ return Byte.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof(UInt16))
+ return UInt16.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof(UInt32))
+ return UInt32.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof(UInt64))
+ return UInt64.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof (Single))
return Single.Parse(str, CultureInfo.InvariantCulture);
- if (toType == typeof (double))
+ if (toType == typeof (Double))
return Double.Parse(str, CultureInfo.InvariantCulture);
- if (toType == typeof (bool))
+ if (toType == typeof (Boolean))
return Boolean.Parse(str);
if (toType == typeof (TimeSpan))
return TimeSpan.Parse(str, CultureInfo.InvariantCulture);
if (toType == typeof (DateTime))
return DateTime.Parse(str, CultureInfo.InvariantCulture);
- if (toType == typeof (string) && str.StartsWith("{}", StringComparison.Ordinal))
+ if (toType == typeof(Char)) {
+ char c = '\0';
+ Char.TryParse(str, out c);
+ return c;
+ }
+ if (toType == typeof (String) && str.StartsWith("{}", StringComparison.Ordinal))
return str.Substring(2);
- if (toType == typeof (string))
+ if (toType == typeof (String))
return value;
+ if (toType == typeof(Decimal))
+ return Decimal.Parse(str, CultureInfo.InvariantCulture);
}
//if there's an implicit conversion, convert