* [Xaml] more builtin conversion, and more type primitives

* [XamlC] more builtin conversion, more type primitives
This commit is contained in:
Stephane Delcroix 2016-09-27 20:10:39 +02:00 коммит произвёл Jason Smith
Родитель 0f7b22f49d
Коммит 3e0ee965d7
8 изменённых файлов: 450 добавлений и 284 удалений

Просмотреть файл

@ -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;
}
}
}

Просмотреть файл

@ -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)

Просмотреть файл

@ -83,5 +83,6 @@
<d:IgnorableElement />
</ContentView.Content>
</ContentView>
<local:MockViewWithValues x:Name="mockView0" UShort="32" ADecimal="42" />
</StackLayout>
</ContentPage>

Просмотреть файл

@ -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);
}
}
}
}

Просмотреть файл

@ -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>

Просмотреть файл

@ -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"];

Просмотреть файл

@ -296,73 +296,87 @@ namespace Xamarin.Forms.Xaml
{
var valuestring = ((ValueNode)node.CollectionItems[0]).Value as string;
if (nodeType == typeof (bool))
if (nodeType == typeof(SByte)) {
sbyte retval;
if (sbyte.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
return retval;
}
if (nodeType == typeof(Int16)) {
short retval;
if (short.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
return retval;
}
if (nodeType == typeof(Int32)) {
int retval;
if (int.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
return retval;
}
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))
return retval;
}
if (nodeType == typeof(Double)) {
double retval;
if (double.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
return retval;
}
if (nodeType == typeof (Boolean))
{
bool outbool;
if (bool.TryParse(valuestring, out outbool))
value = outbool;
return outbool;
}
else if (nodeType == typeof (char))
if (nodeType == typeof(TimeSpan)) {
TimeSpan retval;
if (TimeSpan.TryParse(valuestring, CultureInfo.InvariantCulture, out retval))
return retval;
}
if (nodeType == typeof (char))
{
char retval;
if (char.TryParse(valuestring, out retval))
value = retval;
return retval;
}
else if (nodeType == typeof (string))
value = valuestring;
else if (nodeType == typeof (decimal))
if (nodeType == typeof (string))
return valuestring;
if (nodeType == typeof (decimal))
{
decimal retval;
if (decimal.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
value = retval;
}
else if (nodeType == typeof (float))
{
float retval;
if (float.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
value = retval;
}
else 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;
}
else if (nodeType == typeof (short))
{
short retval;
if (short.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
value = retval;
}
else if (nodeType == typeof (int))
{
int retval;
if (int.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
value = retval;
}
else if (nodeType == typeof (long))
{
long retval;
if (long.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
value = retval;
}
else if (nodeType == typeof (TimeSpan))
{
TimeSpan retval;
if (TimeSpan.TryParse(valuestring, CultureInfo.InvariantCulture, out retval))
value = retval;
return retval;
}
else if (nodeType == typeof (Uri))
{
Uri retval;
if (Uri.TryCreate(valuestring, UriKind.RelativeOrAbsolute, out retval))
value = retval;
return retval;
}
}
return value;

Просмотреть файл

@ -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