public static bool IsDirectlyAssignableFrom(this IXamlIlType type, IXamlIlType other) { if (type.IsValueType || other.IsValueType) { return(type.Equals(other)); } return(type.IsAssignableFrom(other)); }
public IXamlIlCustomAttribute GetCustomAttribute(IXamlIlType type, IXamlIlType attributeType) { if (attributeType.Equals(_typeConverterAttribute)) { var conv = LookupConverter(type); if (conv != null) { return(new ConstructedAttribute(_typeConverterAttribute, new List <object>() { conv }, null)); } } return(null); }
public static void EmitConvert(XamlIlEmitContext context, IXamlIlLineInfo node, IXamlIlType what, IXamlIlType to, Func <bool, IXamlIlEmitter> ld) { if (what.Equals(to)) { ld(false); } else if (what == XamlIlPseudoType.Null) { if (to.IsValueType) { if (to.GenericTypeDefinition?.Equals(context.Configuration.WellKnownTypes.NullableT) == true) { using (var loc = context.GetLocal(to)) ld(false) .Pop() .Ldloca(loc.Local) .Emit(OpCodes.Initobj, to) .Ldloc(loc.Local); } else { throw new XamlIlLoadException("Unable to convert {x:Null} to " + to.GetFqn(), node); } } else { ld(false); } } else if (what.IsValueType && to.IsValueType) { if (to.IsNullableOf(what)) { ld(false).Emit(OpCodes.Newobj, to.Constructors.First(c => c.Parameters.Count == 1 && c.Parameters[0].Equals(what))); } else if (what.IsNullableOf(what)) { ld(true) .EmitCall(what.FindMethod(m => m.Name == "get_Value")); } else { throw new XamlIlLoadException( $"Don't know how to convert value type {what.GetFullName()} to value type {to.GetFullName()}", node); } } else if (!to.IsValueType && what.IsValueType) { if (!to.IsAssignableFrom(what)) { throw new XamlIlLoadException( $"Don't know how to convert value type {what.GetFullName()} to reference type {to.GetFullName()}", node); } ld(false).Box(what); } else if (to.IsValueType && !what.IsValueType) { if (!(what.Namespace == "System" && what.Name == "Object")) { throw new XamlIlLoadException( $"Don't know how to convert reference type {what.GetFullName()} to value type {to.GetFullName()}", node); } ld(false).Unbox_Any(to); } else { if (to.IsAssignableFrom(what)) { // Downcast, always safe ld(false); } else if (what.IsInterface || what.IsAssignableFrom(to)) { // Upcast or cast from interface, might throw InvalidCastException ld(false).Emit(OpCodes.Castclass, to); } else { // Types are completely unrelated, e. g. string to List<int> conversion attempt throw new XamlIlLoadException( $"Don't know how to convert reference type {what.GetFullName()} to reference type {to.GetFullName()}", node); } } }
public static bool TryCallAdd(XamlIlAstTransformationContext context, IXamlIlProperty targetProperty, IXamlIlType targetPropertyType, IXamlIlAstValueNode value, out IXamlIlAstManipulationNode rv) { var so = context.Configuration.WellKnownTypes.Object; rv = null; IXamlIlWrappedMethod FindAdderImpl(IXamlIlType targetType, IXamlIlType valueType, IXamlIlType keyType = null) { var candidates = targetType.FindMethods(m => !m.IsStatic && m.IsPublic && (m.Name == "Add" || m.Name.EndsWith(".Add"))).ToList(); bool CheckArg(IXamlIlType argType, bool allowObj) { if (allowObj && argType.Equals(so)) { return(true); } if (!allowObj && !argType.Equals(so) && argType.IsAssignableFrom(valueType)) { return(true); } return(false); } foreach (var allowObj in new[] { false, true }) { foreach (var m in candidates) { if (keyType == null && m.Parameters.Count == 1 && CheckArg(m.Parameters[0], allowObj)) { return(new XamlIlWrappedMethod(m)); } if (keyType != null && m.Parameters.Count == 2 && m.Parameters[0].IsAssignableFrom(keyType) && CheckArg(m.Parameters[1], allowObj)) { return(new XamlIlWrappedMethod(m)); } } } return(null); } IXamlIlWrappedMethod FindAdderWithCast(IXamlIlType originalType, IXamlIlType newTargetType, IXamlIlType valueType) { var m = FindAdderImpl(newTargetType, valueType); if (m == null) { return(null); } return(new XamlIlWrappedMethodWithCasts(m, new[] { originalType, m.ParametersWithThis[1] })); } IXamlIlWrappedMethod FindAdder(IXamlIlType valueType, IXamlIlType keyType = null) { if (keyType == null) { if (targetPropertyType.Equals(context.Configuration.WellKnownTypes.IEnumerable)) { return(FindAdderWithCast(targetPropertyType, context.Configuration.WellKnownTypes.IList, valueType)); } if (targetPropertyType.GenericTypeDefinition?.Equals(context.Configuration.WellKnownTypes .IEnumerableT) == true) { return(FindAdderWithCast( targetPropertyType, context.Configuration.WellKnownTypes.IListOfT .MakeGenericType(targetPropertyType.GenericArguments[0]), valueType)); } } return(FindAdderImpl(targetPropertyType, valueType, keyType)); } if (TryConvertMarkupExtension(context, value, targetProperty, out var ext)) { var adder = FindAdder(ext.ProvideValue.ReturnType); if (adder != null) { ext.Manipulation = adder; rv = ext; return(true); } } else { var vtype = value.Type.GetClrType(); IXamlIlAstValueNode keyNode = null; bool IsKeyDirective(object node) => node is XamlIlAstXmlDirective d && d.Namespace == XamlNamespaces.Xaml2006 && d.Name == "Key"; void ProcessDirective(object d) { var directive = (XamlIlAstXmlDirective)d; if (directive.Values.Count != 1) { throw new XamlIlParseException("Invalid number of arguments for x:Key directive", directive); } keyNode = directive.Values[0]; } void ProcessDirectiveCandidateList(IList nodes) { var d = nodes.OfType <object>().FirstOrDefault(IsKeyDirective); if (d != null) { ProcessDirective(d); nodes.Remove(d); } } IXamlIlAstManipulationNode VisitManipulationNode(IXamlIlAstManipulationNode man) { if (IsKeyDirective(man)) { ProcessDirective(man); return(new XamlIlManipulationGroupNode(man)); } if (man is XamlIlManipulationGroupNode grp) { ProcessDirectiveCandidateList(grp.Children); } if (man is XamlIlObjectInitializationNode init) { init.Manipulation = VisitManipulationNode(init.Manipulation); } return(man); } if (value is XamlIlAstObjectNode astObject) { ProcessDirectiveCandidateList(astObject.Children); } else if (value is XamlIlValueWithManipulationNode vman) { vman.Manipulation = VisitManipulationNode(vman.Manipulation); } var adder = FindAdder(vtype, keyNode?.Type.GetClrType()); if (adder != null) { var args = new List <IXamlIlAstValueNode>(); if (keyNode != null) { args.Add(keyNode); } args.Add(value); rv = new XamlIlNoReturnMethodCallNode(value, adder, args); if (targetProperty != null) { rv = new XamlIlPropertyValueManipulationNode(value, targetProperty, rv); } return(true); } } return(false); }