зеркало из https://github.com/DeGsoft/maui-linux.git
544 строки
22 KiB
C#
544 строки
22 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.Linq;
|
|
using Mono.Cecil;
|
|
using Mono.Cecil.Cil;
|
|
using Xamarin.Forms.Xaml;
|
|
|
|
namespace Xamarin.Forms.Build.Tasks
|
|
{
|
|
class CreateObjectVisitor : IXamlNodeVisitor
|
|
{
|
|
public CreateObjectVisitor(ILContext context)
|
|
{
|
|
Context = context;
|
|
Module = context.Body.Method.Module;
|
|
}
|
|
|
|
public ILContext Context { get; }
|
|
|
|
ModuleDefinition Module { get; }
|
|
|
|
public bool VisitChildrenFirst
|
|
{
|
|
get { return true; }
|
|
}
|
|
|
|
public bool StopOnDataTemplate
|
|
{
|
|
get { return true; }
|
|
}
|
|
|
|
public bool StopOnResourceDictionary
|
|
{
|
|
get { return false; }
|
|
}
|
|
|
|
public void Visit(ValueNode node, INode parentNode)
|
|
{
|
|
Context.Values[node] = node.Value;
|
|
|
|
XmlName propertyName;
|
|
if (SetPropertiesVisitor.TryGetPropertyName(node, parentNode, out propertyName))
|
|
{
|
|
if (propertyName.NamespaceURI == "http://schemas.openxmlformats.org/markup-compatibility/2006" &&
|
|
propertyName.LocalName == "Ignorable")
|
|
{
|
|
(parentNode.IgnorablePrefixes ?? (parentNode.IgnorablePrefixes = new List<string>())).AddRange(
|
|
(node.Value as string).Split(','));
|
|
}
|
|
}
|
|
}
|
|
|
|
public void Visit(MarkupNode node, INode parentNode)
|
|
{
|
|
//At this point, all MarkupNodes are expanded to ElementNodes
|
|
}
|
|
|
|
public void Visit(ElementNode node, INode parentNode)
|
|
{
|
|
if (node.SkipPrefix((node.NamespaceResolver ?? parentNode.NamespaceResolver).LookupPrefix(node.NamespaceURI)))
|
|
return;
|
|
|
|
var typeref = node.XmlType.GetTypeReference(Module, node);
|
|
TypeDefinition typedef = typeref.Resolve();
|
|
|
|
if (IsXaml2009LanguagePrimitive(node))
|
|
{
|
|
var vardef = new VariableDefinition(typeref);
|
|
Context.Variables[node] = vardef;
|
|
Context.Body.Variables.Add(vardef);
|
|
|
|
Context.IL.Append(PushValueFromLanguagePrimitive(typedef, node));
|
|
Context.IL.Emit(OpCodes.Stloc, vardef);
|
|
}
|
|
else
|
|
{
|
|
MethodDefinition factoryCtorInfo = null;
|
|
MethodDefinition factoryMethodInfo = null;
|
|
MethodDefinition parameterizedCtorInfo = null;
|
|
MethodDefinition ctorInfo = null;
|
|
|
|
if (node.Properties.ContainsKey(XmlName.xArguments) && !node.Properties.ContainsKey(XmlName.xFactoryMethod))
|
|
{
|
|
factoryCtorInfo = typedef.AllMethods().FirstOrDefault(md => md.IsConstructor &&
|
|
!md.IsStatic &&
|
|
md.HasParameters &&
|
|
md.MatchXArguments(node, Module));
|
|
if (factoryCtorInfo == null)
|
|
{
|
|
throw new XamlParseException(
|
|
string.Format("No constructors found for {0} with matching x:Arguments", typedef.FullName), node);
|
|
}
|
|
ctorInfo = factoryCtorInfo;
|
|
if (!typedef.IsValueType) //for ctor'ing typedefs, we first have to ldloca before the params
|
|
Context.IL.Append(PushCtorXArguments(factoryCtorInfo, node));
|
|
}
|
|
else if (node.Properties.ContainsKey(XmlName.xFactoryMethod))
|
|
{
|
|
var factoryMethod = (string)(node.Properties[XmlName.xFactoryMethod] as ValueNode).Value;
|
|
factoryMethodInfo = typedef.AllMethods().FirstOrDefault(md => !md.IsConstructor &&
|
|
md.Name == factoryMethod &&
|
|
md.IsStatic &&
|
|
md.MatchXArguments(node, Module));
|
|
if (factoryMethodInfo == null)
|
|
{
|
|
throw new XamlParseException(
|
|
String.Format("No static method found for {0}::{1} ({2})", typedef.FullName, factoryMethod, null), node);
|
|
}
|
|
Context.IL.Append(PushCtorXArguments(factoryMethodInfo, node));
|
|
}
|
|
if (ctorInfo == null && factoryMethodInfo == null)
|
|
{
|
|
parameterizedCtorInfo = typedef.Methods.FirstOrDefault(md => md.IsConstructor &&
|
|
!md.IsStatic &&
|
|
md.HasParameters &&
|
|
md.Parameters.All(
|
|
pd =>
|
|
pd.CustomAttributes.Any(
|
|
ca =>
|
|
ca.AttributeType.FullName ==
|
|
"Xamarin.Forms.ParameterAttribute")));
|
|
}
|
|
if (parameterizedCtorInfo != null && ValidateCtorArguments(parameterizedCtorInfo, node))
|
|
{
|
|
ctorInfo = parameterizedCtorInfo;
|
|
// IL_0000: ldstr "foo"
|
|
Context.IL.Append(PushCtorArguments(parameterizedCtorInfo, node));
|
|
}
|
|
ctorInfo = ctorInfo ?? typedef.Methods.FirstOrDefault(md => md.IsConstructor && !md.HasParameters && !md.IsStatic);
|
|
|
|
var ctorinforef = ctorInfo?.ResolveGenericParameters(typeref, Module);
|
|
var factorymethodinforef = factoryMethodInfo?.ResolveGenericParameters(typeref, Module);
|
|
var implicitOperatorref = typedef.Methods.FirstOrDefault(md =>
|
|
md.IsPublic &&
|
|
md.IsStatic &&
|
|
md.IsSpecialName &&
|
|
md.Name == "op_Implicit" && md.Parameters[0].ParameterType.FullName == "System.String");
|
|
|
|
if (ctorinforef != null || factorymethodinforef != null || typedef.IsValueType)
|
|
{
|
|
VariableDefinition vardef = new VariableDefinition(typeref);
|
|
Context.Variables[node] = vardef;
|
|
Context.Body.Variables.Add(vardef);
|
|
|
|
ValueNode vnode = null;
|
|
if (node.CollectionItems.Count == 1 && (vnode = node.CollectionItems.First() as ValueNode) != null &&
|
|
vardef.VariableType.IsValueType)
|
|
{
|
|
//<Color>Purple</Color>
|
|
Context.IL.Append(vnode.PushConvertedValue(Context, typeref, new ICustomAttributeProvider[] { typedef },
|
|
node.PushServiceProvider(Context), false, true));
|
|
Context.IL.Emit(OpCodes.Stloc, vardef);
|
|
}
|
|
else if (node.CollectionItems.Count == 1 && (vnode = node.CollectionItems.First() as ValueNode) != null &&
|
|
implicitOperatorref != null)
|
|
{
|
|
//<FileImageSource>path.png</FileImageSource>
|
|
var implicitOperator = Module.Import(implicitOperatorref);
|
|
Context.IL.Emit(OpCodes.Ldstr, ((ValueNode)(node.CollectionItems.First())).Value as string);
|
|
Context.IL.Emit(OpCodes.Call, implicitOperator);
|
|
Context.IL.Emit(OpCodes.Stloc, vardef);
|
|
}
|
|
else if (factorymethodinforef != null)
|
|
{
|
|
var factory = Module.Import(factorymethodinforef);
|
|
Context.IL.Emit(OpCodes.Call, factory);
|
|
Context.IL.Emit(OpCodes.Stloc, vardef);
|
|
}
|
|
else if (!typedef.IsValueType)
|
|
{
|
|
var ctor = Module.Import(ctorinforef);
|
|
// IL_0001: newobj instance void class [Xamarin.Forms.Core]Xamarin.Forms.Button::'.ctor'()
|
|
// IL_0006: stloc.0
|
|
Context.IL.Emit(OpCodes.Newobj, ctor);
|
|
Context.IL.Emit(OpCodes.Stloc, vardef);
|
|
}
|
|
else if (ctorInfo != null && node.Properties.ContainsKey(XmlName.xArguments) &&
|
|
!node.Properties.ContainsKey(XmlName.xFactoryMethod) && ctorInfo.MatchXArguments(node, Module))
|
|
{
|
|
// IL_0008: ldloca.s 1
|
|
// IL_000a: ldc.i4.1
|
|
// IL_000b: call instance void valuetype Test/Foo::'.ctor'(bool)
|
|
|
|
var ctor = Module.Import(ctorinforef);
|
|
Context.IL.Emit(OpCodes.Ldloca, vardef);
|
|
Context.IL.Append(PushCtorXArguments(factoryCtorInfo, node));
|
|
Context.IL.Emit(OpCodes.Call, ctor);
|
|
}
|
|
else
|
|
{
|
|
// IL_0000: ldloca.s 0
|
|
// IL_0002: initobj Test/Foo
|
|
Context.IL.Emit(OpCodes.Ldloca, vardef);
|
|
Context.IL.Emit(OpCodes.Initobj, Module.Import(typedef));
|
|
}
|
|
|
|
if (typeref.FullName == "Xamarin.Forms.Xaml.TypeExtension")
|
|
{
|
|
var visitor = new SetPropertiesVisitor(Context);
|
|
foreach (var cnode in node.Properties.Values.ToList())
|
|
cnode.Accept(visitor, node);
|
|
foreach (var cnode in node.CollectionItems)
|
|
cnode.Accept(visitor, node);
|
|
|
|
//As we're stripping the TypeExtension bare, keep the type if we need it later (hint: we do need it)
|
|
INode ntype;
|
|
if (!node.Properties.TryGetValue(new XmlName("", "TypeName"), out ntype))
|
|
ntype = node.CollectionItems[0];
|
|
|
|
var type = ((ValueNode)ntype).Value as string;
|
|
var namespaceuri = type.Contains(":") ? node.NamespaceResolver.LookupNamespace(type.Split(':')[0].Trim()) : "";
|
|
type = type.Contains(":") ? type.Split(':')[1].Trim() : type;
|
|
Context.TypeExtensions[node] = new XmlType(namespaceuri, type, null).GetTypeReference(Module, node);
|
|
|
|
node.Properties.Clear();
|
|
node.CollectionItems.Clear();
|
|
|
|
var vardefref = new VariableDefinitionReference(vardef);
|
|
Context.IL.Append(SetPropertiesVisitor.ProvideValue(vardefref, Context, Module, node));
|
|
if (vardef != vardefref.VariableDefinition)
|
|
{
|
|
Context.Variables[node] = vardefref.VariableDefinition;
|
|
Context.Body.Variables.Add(vardefref.VariableDefinition);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void Visit(RootNode node, INode parentNode)
|
|
{
|
|
// IL_0013: ldarg.0
|
|
// IL_0014: stloc.3
|
|
|
|
var ilnode = (ILRootNode)node;
|
|
var typeref = ilnode.TypeReference;
|
|
var vardef = new VariableDefinition(typeref);
|
|
Context.Variables[node] = vardef;
|
|
Context.Root = vardef;
|
|
Context.Body.Variables.Add(vardef);
|
|
Context.IL.Emit(OpCodes.Ldarg_0);
|
|
Context.IL.Emit(OpCodes.Stloc, vardef);
|
|
}
|
|
|
|
public void Visit(ListNode node, INode parentNode)
|
|
{
|
|
XmlName name;
|
|
if (SetPropertiesVisitor.TryGetPropertyName(node, parentNode, out name))
|
|
node.XmlName = name;
|
|
}
|
|
|
|
bool ValidateCtorArguments(MethodDefinition ctorinfo, ElementNode enode)
|
|
{
|
|
foreach (var parameter in ctorinfo.Parameters)
|
|
{
|
|
var propname =
|
|
parameter.CustomAttributes.First(ca => ca.AttributeType.FullName == "Xamarin.Forms.ParameterAttribute")
|
|
.ConstructorArguments.First()
|
|
.Value as string;
|
|
if (!enode.Properties.ContainsKey(new XmlName("", propname)))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
IEnumerable<Instruction> PushCtorArguments(MethodDefinition ctorinfo, ElementNode enode)
|
|
{
|
|
foreach (var parameter in ctorinfo.Parameters)
|
|
{
|
|
var propname =
|
|
parameter.CustomAttributes.First(ca => ca.AttributeType.FullName == "Xamarin.Forms.ParameterAttribute")
|
|
.ConstructorArguments.First()
|
|
.Value as string;
|
|
var node = enode.Properties[new XmlName("", propname)];
|
|
enode.Properties.Remove(new XmlName("", propname));
|
|
VariableDefinition vardef;
|
|
ValueNode vnode = null;
|
|
|
|
if (node is IElementNode && (vardef = Context.Variables[node as IElementNode]) != null)
|
|
yield return Instruction.Create(OpCodes.Ldloc, vardef);
|
|
else if ((vnode = node as ValueNode) != null)
|
|
{
|
|
foreach (var instruction in vnode.PushConvertedValue(Context,
|
|
parameter.ParameterType,
|
|
new ICustomAttributeProvider[] { parameter, parameter.ParameterType.Resolve() },
|
|
enode.PushServiceProvider(Context), false, true))
|
|
yield return instruction;
|
|
}
|
|
}
|
|
}
|
|
|
|
IEnumerable<Instruction> PushCtorXArguments(MethodDefinition factoryCtorInfo, ElementNode enode)
|
|
{
|
|
if (!enode.Properties.ContainsKey(XmlName.xArguments))
|
|
yield break;
|
|
|
|
var arguments = new List<INode>();
|
|
var node = enode.Properties[XmlName.xArguments] as ElementNode;
|
|
if (node != null)
|
|
arguments.Add(node);
|
|
var list = enode.Properties[XmlName.xArguments] as ListNode;
|
|
if (list != null)
|
|
{
|
|
foreach (var n in list.CollectionItems)
|
|
arguments.Add(n);
|
|
}
|
|
|
|
for (var i = 0; i < factoryCtorInfo.Parameters.Count; i++)
|
|
{
|
|
var parameter = factoryCtorInfo.Parameters[i];
|
|
var arg = arguments[i];
|
|
VariableDefinition vardef;
|
|
ValueNode vnode = null;
|
|
|
|
if (arg is IElementNode && (vardef = Context.Variables[arg as IElementNode]) != null)
|
|
yield return Instruction.Create(OpCodes.Ldloc, vardef);
|
|
else if ((vnode = arg as ValueNode) != null)
|
|
{
|
|
foreach (var instruction in vnode.PushConvertedValue(Context,
|
|
parameter.ParameterType,
|
|
new ICustomAttributeProvider[] { parameter, parameter.ParameterType.Resolve() },
|
|
enode.PushServiceProvider(Context), false, true))
|
|
yield return instruction;
|
|
}
|
|
}
|
|
}
|
|
|
|
static bool IsXaml2009LanguagePrimitive(IElementNode node)
|
|
{
|
|
if (node.NamespaceURI == "http://schemas.microsoft.com/winfx/2009/xaml")
|
|
return true;
|
|
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")
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
IEnumerable<Instruction> PushValueFromLanguagePrimitive(TypeDefinition typedef, ElementNode node)
|
|
{
|
|
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":
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
} |