Esempio n. 1
0
        /// <summary>
        /// Gets the underlying element type.
        /// </summary>
        /// <param name="type">The type to extract the underlying type (if any).</param>
        /// <returns>The underlying element type.</returns>
        /// <returns>The underlying type.</returns>
        public static Type GetUnderlyingType(TypeInfo type)
        {
            if (type.IsArray)
            {
                return type.GetElementType();
            }

            if (type.IsGenericType == false)
            {
                return type.AsType();
            }

            Type enumerableType;
            if (TryGetEnumerableType(type, out enumerableType))
            {
                return enumerableType.GetTypeInfo().GenericTypeArguments[0]; ;
            }

            return type.AsType();
        }
Esempio n. 2
0
        /// <summary>
        /// Resolves <see cref="System.Type"/> to a <see cref="TypeSymbol"/> available in this assembly
        /// its referenced assemblies.
        /// </summary>
        /// <param name="type">The type to resolve.</param>
        /// <param name="includeReferences">Use referenced assemblies for resolution.</param>
        /// <returns>The resolved symbol if successful or null on failure.</returns>
        internal TypeSymbol GetTypeByReflectionType(Type type, bool includeReferences)
        {
            System.Reflection.TypeInfo typeInfo = type.GetTypeInfo();

            Debug.Assert(!typeInfo.IsByRef);

            // not supported rigth now (we don't accept open types as submission results nor host types):
            Debug.Assert(!typeInfo.ContainsGenericParameters);

            if (typeInfo.IsArray)
            {
                TypeSymbol symbol = GetTypeByReflectionType(typeInfo.GetElementType(), includeReferences);
                if ((object)symbol == null)
                {
                    return(null);
                }

                int rank = typeInfo.GetArrayRank();
                return(new ArrayTypeSymbol(this, symbol, ImmutableArray <CustomModifier> .Empty, rank));
            }
            else if (typeInfo.IsPointer)
            {
                TypeSymbol symbol = GetTypeByReflectionType(typeInfo.GetElementType(), includeReferences);
                if ((object)symbol == null)
                {
                    return(null);
                }

                return(new PointerTypeSymbol(symbol));
            }
            else if (typeInfo.DeclaringType != null)
            {
                Debug.Assert(!typeInfo.IsArray);

                // consolidated generic arguments (includes arguments of all declaring types):
                Type[] genericArguments  = typeInfo.GenericTypeArguments;
                int    typeArgumentIndex = 0;

                var currentTypeInfo = typeInfo.IsGenericType ? typeInfo.GetGenericTypeDefinition().GetTypeInfo() : typeInfo;
                var nestedTypes     = ArrayBuilder <System.Reflection.TypeInfo> .GetInstance();

                while (true)
                {
                    Debug.Assert(currentTypeInfo.IsGenericTypeDefinition || !currentTypeInfo.IsGenericType);

                    nestedTypes.Add(currentTypeInfo);
                    if (currentTypeInfo.DeclaringType == null)
                    {
                        break;
                    }

                    currentTypeInfo = currentTypeInfo.DeclaringType.GetTypeInfo();
                }

                int i      = nestedTypes.Count - 1;
                var symbol = (NamedTypeSymbol)GetTypeByReflectionType(nestedTypes[i].AsType(), includeReferences);
                if ((object)symbol == null)
                {
                    return(null);
                }

                while (--i >= 0)
                {
                    int forcedArity         = nestedTypes[i].GenericTypeParameters.Length - nestedTypes[i + 1].GenericTypeParameters.Length;
                    MetadataTypeName mdName = MetadataTypeName.FromTypeName(nestedTypes[i].Name, forcedArity: forcedArity);

                    symbol = symbol.LookupMetadataType(ref mdName);
                    if ((object)symbol == null || symbol.IsErrorType())
                    {
                        return(null);
                    }

                    symbol = ApplyGenericArguments(symbol, genericArguments, ref typeArgumentIndex, includeReferences);
                    if ((object)symbol == null)
                    {
                        return(null);
                    }
                }

                nestedTypes.Free();
                Debug.Assert(typeArgumentIndex == genericArguments.Length);
                return(symbol);
            }
            else
            {
                AssemblyIdentity assemblyId = AssemblyIdentity.FromAssemblyDefinition(typeInfo.Assembly);

                MetadataTypeName mdName = MetadataTypeName.FromNamespaceAndTypeName(
                    typeInfo.Namespace ?? string.Empty,
                    typeInfo.Name,
                    forcedArity: typeInfo.GenericTypeArguments.Length);

                NamedTypeSymbol symbol = GetTopLevelTypeByMetadataName(ref mdName, assemblyId, includeReferences, isWellKnownType: false);

                if ((object)symbol == null || symbol.IsErrorType())
                {
                    return(null);
                }

                int    typeArgumentIndex = 0;
                Type[] genericArguments  = typeInfo.GenericTypeArguments;
                symbol = ApplyGenericArguments(symbol, genericArguments, ref typeArgumentIndex, includeReferences);
                Debug.Assert(typeArgumentIndex == genericArguments.Length);
                return(symbol);
            }
        }
Esempio n. 3
0
        void SetupPart(System.Reflection.TypeInfo sourceType, BindingExpressionPart part)
        {
            part.Arguments  = null;
            part.LastGetter = null;
            part.LastSetter = null;

            PropertyInfo property = null;

            if (part.IsIndexer)
            {
                if (sourceType.IsArray)
                {
                    int index;
                    if (!int.TryParse(part.Content, NumberStyles.Number, CultureInfo.InvariantCulture, out index))
                    {
                        Console.WriteLine($"Binding : {part.Content} could not be parsed as an index for a {sourceType}");
                    }
                    else
                    {
                        part.Arguments = new object[] { index }
                    };

                    part.LastGetter = sourceType.GetDeclaredMethod("Get");
                    part.LastSetter = sourceType.GetDeclaredMethod("Set");
                    part.SetterType = sourceType.GetElementType();
                }

                DefaultMemberAttribute defaultMember = sourceType.GetCustomAttributes(typeof(DefaultMemberAttribute), true).OfType <DefaultMemberAttribute>().FirstOrDefault();
                string indexerName = defaultMember != null ? defaultMember.MemberName : "Item";

                part.IndexerName = indexerName;

#if NETSTANDARD2_0
                try
                {
                    property = sourceType.GetDeclaredProperty(indexerName);
                }
                catch (AmbiguousMatchException)
                {
                    // Get most derived instance of property
                    foreach (var p in sourceType.GetProperties().Where(prop => prop.Name == indexerName))
                    {
                        if (property == null || property.DeclaringType.IsAssignableFrom(property.DeclaringType))
                        {
                            property = p;
                        }
                    }
                }
#else
                property = sourceType.GetDeclaredProperty(indexerName);
#endif

                if (property == null) //is the indexer defined on the base class?
                {
                    property = sourceType.BaseType?.GetProperty(indexerName);
                }
                if (property == null) //is the indexer defined on implemented interface ?
                {
                    foreach (var implementedInterface in sourceType.ImplementedInterfaces)
                    {
                        property = implementedInterface.GetProperty(indexerName);
                        if (property != null)
                        {
                            break;
                        }
                    }
                }

                if (property != null)
                {
                    ParameterInfo parameter = property.GetIndexParameters().FirstOrDefault();
                    if (parameter != null)
                    {
                        try
                        {
                            object arg = Convert.ChangeType(part.Content, parameter.ParameterType, CultureInfo.InvariantCulture);
                            part.Arguments = new[] { arg };
                        }
                        catch (FormatException)
                        {
                        }
                        catch (InvalidCastException)
                        {
                        }
                        catch (OverflowException)
                        {
                        }
                    }
                }
            }
            else
            {
                property = sourceType.GetDeclaredProperty(part.Content) ?? sourceType.BaseType?.GetProperty(part.Content);
            }

            if (property != null)
            {
                if (property.CanRead && property.GetMethod != null)
                {
                    if (property.GetMethod.IsPublic && !property.GetMethod.IsStatic)
                    {
                        part.LastGetter = property.GetMethod;
                    }
                }
                if (property.CanWrite && property.SetMethod != null)
                {
                    if (property.SetMethod.IsPublic && !property.SetMethod.IsStatic)
                    {
                        part.LastSetter = property.SetMethod;
                        part.SetterType = part.LastSetter.GetParameters().Last().ParameterType;

                        if (Binding.AllowChaining)
                        {
                            FieldInfo bindablePropertyField = sourceType.GetDeclaredField(part.Content + "Property");
                            if (bindablePropertyField != null && bindablePropertyField.FieldType == typeof(BindableProperty) && sourceType.ImplementedInterfaces.Contains(typeof(IElementController)))
                            {
                                MethodInfo setValueMethod = null;
#if NETSTANDARD1_0
                                foreach (MethodInfo m in sourceType.AsType().GetRuntimeMethods())
                                {
                                    if (m.Name.EndsWith("IElementController.SetValueFromRenderer"))
                                    {
                                        ParameterInfo[] parameters = m.GetParameters();
                                        if (parameters.Length == 2 && parameters[0].ParameterType == typeof(BindableProperty))
                                        {
                                            setValueMethod = m;
                                            break;
                                        }
                                    }
                                }
#else
                                setValueMethod = typeof(IElementController).GetMethod("SetValueFromRenderer", new[] { typeof(BindableProperty), typeof(object) });
#endif
                                if (setValueMethod != null)
                                {
                                    part.LastSetter = setValueMethod;
                                    part.IsBindablePropertySetter = true;
                                    part.BindablePropertyField    = bindablePropertyField.GetValue(null);
                                }
                            }
                        }
                    }
                }
#if !NETSTANDARD1_0
                //TupleElementNamesAttribute tupleEltNames;
                //if (property != null
                //    && part.NextPart != null
                //    && property.PropertyType.IsGenericType
                //    && (property.PropertyType.GetGenericTypeDefinition() == typeof(ValueTuple<>)
                //        || property.PropertyType.GetGenericTypeDefinition() == typeof(ValueTuple<,>)
                //        || property.PropertyType.GetGenericTypeDefinition() == typeof(ValueTuple<,,>)
                //        || property.PropertyType.GetGenericTypeDefinition() == typeof(ValueTuple<,,,>)
                //        || property.PropertyType.GetGenericTypeDefinition() == typeof(ValueTuple<,,,,>)
                //        || property.PropertyType.GetGenericTypeDefinition() == typeof(ValueTuple<,,,,,>)
                //        || property.PropertyType.GetGenericTypeDefinition() == typeof(ValueTuple<,,,,,,>)
                //        || property.PropertyType.GetGenericTypeDefinition() == typeof(ValueTuple<,,,,,,,>))
                //    && (tupleEltNames = property.GetCustomAttribute(typeof(TupleElementNamesAttribute)) as TupleElementNamesAttribute) != null)
                //{
                //    // modify the nextPart to access the tuple item via the ITuple indexer
                //    var nextPart = part.NextPart;
                //    var name = nextPart.Content;
                //    var index = tupleEltNames.TransformNames.IndexOf(name);
                //    if (index >= 0)
                //    {
                //        nextPart.IsIndexer = true;
                //        nextPart.Content = index.ToString();
                //    }
                //}
#endif
            }
        }
Esempio n. 4
0
        private static CreateMethod CreateObjectActivator(TypeInfo typeInfo, out object firstResult)
        {
            CreateMethod activator;
            firstResult = null;

            // Filter out non-instantiatable Types
            if (typeInfo.IsAbstract || typeInfo.IsInterface || typeInfo.IsGenericTypeDefinition)
            {
                activator = nullObjectActivator;
            }
            // If the caller wants a string, just return an empty one
            else if (typeInfo.AsType() == typeof(string))
            {
                activator = () => "";
            }
            // If the caller wants an array, create an empty one
            else if (typeInfo.IsArray && typeInfo.GetArrayRank() == 1)
            {
                activator = () => Array.CreateInstance(typeInfo.GetElementType(), 0);
            }
            // For structs, boxing a default(T) is sufficient
            else if (typeInfo.IsValueType)
            {
                var lambda = Expression.Lambda<CreateMethod>(Expression.Convert(Expression.Default(typeInfo.AsType()), typeof(object)));
                activator = lambda.Compile();
            }
            else
            {
                activator = nullObjectActivator;

                // Retrieve constructors, sorted from trivial to parameter-rich
                ConstructorInfo[] constructors = typeInfo.DeclaredConstructors
                    .Where(c => !c.IsStatic)
                    .Select(c => new { Info = c, ParamCount = c.GetParameters().Length })
                    .OrderBy(s => s.ParamCount)
                    .Select(s => s.Info)
                    .ToArray();

                Exception lastError = null;
                foreach (ConstructorInfo con in constructors)
                {
                    // Prepare constructor argument values - just use default(T) for all of them.
                    ParameterInfo[] conParams = con.GetParameters();
                    Expression[] args = new Expression[conParams.Length];
                    for (int i = 0; i < args.Length; i++)
                    {
                        Type paramType = conParams[i].ParameterType;
                        args[i] = Expression.Default(paramType);
                    }

                    // Compile a lambda method invoking the constructor
                    var lambda = Expression.Lambda<CreateMethod>(Expression.New(con, args));
                    activator = lambda.Compile();

                    // Does it work?
                    firstResult = CheckActivator(activator, out lastError);
                    if (firstResult != null)
                        break;
                }

                // If all constructors failed, inform someone. This is not ideal.
                if (firstResult == null)
                {
                    Log.Core.WriteWarning("Failed to create object of Type {0}. Make sure there is a trivial constructor.", Log.Type(typeInfo));
                }
            }

            // Test whether our activation method really works, replace with dummy if not
            if (firstResult == null)
            {
                Exception error;
                firstResult = CheckActivator(activator, out error);

                // If we fail to initialize the Type due to a problem in its static constructor, it's likely a user problem. Let him know.
                if (error is TypeInitializationException)
                {
                    Log.Core.WriteError("Failed to initialize Type {0}: {1}",
                        Log.Type(typeInfo),
                        Log.Exception(error.InnerException));
                }
            }

            // If we still don't have anything, just use a dummy.
            if (firstResult == null)
                activator = nullObjectActivator;

            return activator;
        }
Esempio n. 5
0
        // Method to compare two types pointers for type equality
        // We cannot just compare the pointers as there can be duplicate type instances
        // for cloned and constructed types.
        static bool AreTypesEquivalentInternal(TypeInfo pType1, TypeInfo pType2)
        {
            if (!pType1.IsInstantiatedTypeInfo() && !pType2.IsInstantiatedTypeInfo())
                return pType1.Equals(pType2);

            if (pType1.IsGenericType && pType2.IsGenericType)
            {
                if (!pType1.GetGenericTypeDefinition().Equals(pType2.GetGenericTypeDefinition()))
                    return false;

                Type[] args1 = pType1.GenericTypeArguments;
                Type[] args2 = pType2.GenericTypeArguments;
                Debug.Assert(args1.Length == args2.Length);

                for (int i = 0; i < args1.Length; i++)
                {
                    if (!AreTypesEquivalentInternal(args1[i].GetTypeInfo(), args2[i].GetTypeInfo()))
                        return false;
                }

                return true;
            }

            if (pType1.IsArray && pType2.IsArray)
            {
                if (pType1.GetArrayRank() != pType2.GetArrayRank())
                    return false;

                return AreTypesEquivalentInternal(pType1.GetElementType().GetTypeInfo(), pType2.GetElementType().GetTypeInfo());
            }

            if (pType1.IsPointer && pType2.IsPointer)
            {
                return AreTypesEquivalentInternal(pType1.GetElementType().GetTypeInfo(), pType2.GetElementType().GetTypeInfo());
            }

            return false;
        }
Esempio n. 6
0
        // Internally callable version of the export method above. Has two additional parameters:
        //  fBoxedSource            : assume the source type is boxed so that value types and enums are
        //                            compatible with Object, ValueType and Enum (if applicable)
        //  fAllowSizeEquivalence   : allow identically sized integral types and enums to be considered
        //                            equivalent (currently used only for array element types)
        static bool AreTypesAssignableInternal(TypeInfo pSourceType, TypeInfo pTargetType, bool fBoxedSource, bool fAllowSizeEquivalence)
        {
            //
            // Are the types identical?
            //
            if (AreTypesEquivalentInternal(pSourceType, pTargetType))
                return true;

            //
            // Handle cast to interface cases.
            //
            if (pTargetType.IsInterface)
            {
                // Value types can only be cast to interfaces if they're boxed.
                if (!fBoxedSource && pSourceType.IsValueType)
                    return false;

                if (ImplementsInterface(pSourceType, pTargetType))
                    return true;

                // Are the types compatible due to generic variance?
                // if (pTargetType.HasGenericVariance && pSourceType.HasGenericVariance)
                if (pTargetType.IsGenericType && pSourceType.IsGenericType)
                    return TypesAreCompatibleViaGenericVariance(pSourceType, pTargetType);

                return false;
            }
            if (pSourceType.IsInterface)
            {
                // The only non-interface type an interface can be cast to is Object.
                return pTargetType.IsSystemObject();
            }

            //
            // Handle cast to array cases.
            //
            if (pTargetType.IsArray)
            {
                if (pSourceType.IsArray)
                {
                    if (pSourceType.GetElementType().GetTypeInfo().IsPointer)
                    {
                        // If the element types are pointers, then only exact matches are correct.
                        // As we've already called AreTypesEquivalent at the start of this function,
                        // return false as the exact match case has already been handled.
                        // int** is not compatible with uint**, nor is int*[] oompatible with uint*[].
                        return false;
                    }
                    else
                    {
                        // Source type is also a pointer. Are the element types compatible? Note that using
                        // AreTypesAssignableInternal here handles array covariance as well as IFoo[] . Foo[]
                        // etc. Pass false for fBoxedSource since int[] is not assignable to object[].
                        return AreTypesAssignableInternal(pSourceType.GetElementType().GetTypeInfo(), pTargetType.GetElementType().GetTypeInfo(), false, true);
                    }
                }

                // Can't cast a non-array type to an array.
                return false;
            }
            if (pSourceType.IsArray)
            {
                // Target type is not an array. But we can still cast arrays to Object or System.Array.
                return pTargetType.IsSystemObject() || pTargetType.IsSystemArray();
            }

            //
            // Handle pointer cases
            //
            if (pTargetType.IsPointer)
            {
                if (pSourceType.IsPointer)
                {
                    if (pSourceType.GetElementType().GetTypeInfo().IsPointer)
                    {
                        // If the element types are pointers, then only exact matches are correct.
                        // As we've already called AreTypesEquivalent at the start of this function,
                        // return false as the exact match case has already been handled.
                        // int** is not compatible with uint**, nor is int*[] compatible with uint*[].
                        return false;
                    }
                    else
                    {
                        // Source type is also a pointer. Are the element types compatible? Note that using
                        // AreTypesAssignableInternal here handles array covariance as well as IFoo[] . Foo[]
                        // etc. Pass false for fBoxedSource since int[] is not assignable to object[].
                        return AreTypesAssignableInternal(pSourceType.GetElementType().GetTypeInfo(), pTargetType.GetElementType().GetTypeInfo(), false, true);
                    }
                }

                return false;
            }
            else if (pSourceType.IsPointer)
            {
                return false;
            }

            //
            // Handle cast to other (non-interface, non-array) cases.
            //

            if (pSourceType.IsValueType)
            {
                // Certain value types of the same size are treated as equivalent when the comparison is
                // between array element types (indicated by fAllowSizeEquivalence). These are integer types
                // of the same size (e.g. int and uint) and the base type of enums vs all integer types of the
                // same size.
                if (fAllowSizeEquivalence && pTargetType.IsValueType)
                {
                    if (ArePrimitveTypesEquivalentSize(pSourceType, pTargetType))
                        return true;

                    // Non-identical value types aren't equivalent in any other case (since value types are
                    // sealed).
                    return false;
                }

                // If the source type is a value type but it's not boxed then we've run out of options: the types
                // are not identical, the target type isn't an interface and we're not allowed to check whether
                // the target type is a parent of this one since value types are sealed and thus the only matches
                // would be against Object, ValueType or Enum, all of which are reference types and not compatible
                // with non-boxed value types.
                if (!fBoxedSource)
                    return false;
            }

            //
            // Are the types compatible via generic variance?
            //
            // if (pTargetType.HasGenericVariance && pSourceType.HasGenericVariance)
            if (pTargetType.IsGenericType && pSourceType.IsGenericType)
            {
                if (TypesAreCompatibleViaGenericVariance(pSourceType, pTargetType))
                    return true;
            }

            // Is the source type derived from the target type?
            if (IsDerived(pSourceType, pTargetType))
                return true;

            return false;
        }
Esempio n. 7
0
		protected override string GetTypeName (TypeInfo type)
		{
			if (type.IsGenericType) {
				return base.GetTypeName(type) + "<" + 
					string.Join (", ", type.GenericTypeArguments.Select (p => GetTypeName (p))) + ">";
			} 

			if (type.IsArray && type.HasElementType && type.GetElementType().GetTypeInfo().IsGenericType) {
				return GetTypeName (type.GetElementType ()) + string.Join("", 
					Enumerable.Range (0, type.GetArrayRank ()).Select (_ => "[]"));
			}

			return base.GetTypeName (type).TrimEnd ('&');
		}
Esempio n. 8
0
        private static bool CanCastTo(this TypeInfo fromTypeInfo, TypeInfo toTypeInfo, FoundationTypes foundationTypes)
        {
            if (fromTypeInfo.Equals(toTypeInfo))
                return true;

            if (fromTypeInfo.IsArray)
            {
                if (toTypeInfo.IsInterface)
                    return fromTypeInfo.CanCastArrayToInterface(toTypeInfo, foundationTypes);

                Type toType = toTypeInfo.AsType();
                if (fromTypeInfo.IsSubclassOf(toType))
                    return true;  // T[] is castable to Array or Object.

                if (!toTypeInfo.IsArray) 
                    return false;

                int rank = fromTypeInfo.GetArrayRank();
                if (rank != toTypeInfo.GetArrayRank())
                    return false;

                bool fromTypeIsSzArray = fromTypeInfo.IsSzArray(foundationTypes);
                bool toTypeIsSzArray = toTypeInfo.IsSzArray(foundationTypes);
                if (fromTypeIsSzArray != toTypeIsSzArray)
                {
                    // T[] is assignable to T[*] but not vice-versa.
                    if (!(rank == 1 && !toTypeIsSzArray))
                    {
                        return false; // T[*] is not castable to T[]
                    }
                }

                TypeInfo toElementTypeInfo = toTypeInfo.GetElementType().GetTypeInfo();
                TypeInfo fromElementTypeInfo = fromTypeInfo.GetElementType().GetTypeInfo();
                return fromElementTypeInfo.IsElementTypeCompatibleWith(toElementTypeInfo, foundationTypes);
            }

            if (fromTypeInfo.IsByRef)
            {
                if (!toTypeInfo.IsByRef)
                    return false;

                TypeInfo toElementTypeInfo = toTypeInfo.GetElementType().GetTypeInfo();
                TypeInfo fromElementTypeInfo = fromTypeInfo.GetElementType().GetTypeInfo();
                return fromElementTypeInfo.IsElementTypeCompatibleWith(toElementTypeInfo, foundationTypes);
            }

            if (fromTypeInfo.IsPointer)
            {
                Type toType = toTypeInfo.AsType();
                if (toType.Equals(foundationTypes.SystemObject))
                    return true;  // T* is castable to Object.

                if (toType.Equals(foundationTypes.SystemUIntPtr))
                    return true;  // T* is castable to UIntPtr (but not IntPtr)

                if (!toTypeInfo.IsPointer)
                    return false;

                TypeInfo toElementTypeInfo = toTypeInfo.GetElementType().GetTypeInfo();
                TypeInfo fromElementTypeInfo = fromTypeInfo.GetElementType().GetTypeInfo();
                return fromElementTypeInfo.IsElementTypeCompatibleWith(toElementTypeInfo, foundationTypes);
            }

            if (fromTypeInfo.IsGenericParameter)
            {
                //
                // A generic parameter can be cast to any of its constraints, or object, if none are specified, or ValueType if the "struct" constraint is
                // specified.
                //
                // This has to be coded as its own case as TypeInfo.BaseType on a generic parameter doesn't always return what you'd expect.
                //
                Type toType = toTypeInfo.AsType();
                if (toType.Equals(foundationTypes.SystemObject))
                    return true;

                if (toType.Equals(foundationTypes.SystemValueType))
                {
                    GenericParameterAttributes attributes = fromTypeInfo.GenericParameterAttributes;
                    if ((attributes & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0)
                        return true;
                }

                foreach (Type constraintType in fromTypeInfo.GetGenericParameterConstraints())
                {
                    if (constraintType.GetTypeInfo().CanCastTo(toTypeInfo, foundationTypes))
                        return true;
                }

                return false;
            }

            if (toTypeInfo.IsArray || toTypeInfo.IsByRef || toTypeInfo.IsPointer || toTypeInfo.IsGenericParameter)
                return false;

            if (fromTypeInfo.MatchesWithVariance(toTypeInfo, foundationTypes))
                return true;

            if (toTypeInfo.IsInterface)
            {
                foreach (Type ifc in fromTypeInfo.ImplementedInterfaces)
                {
                    if (ifc.GetTypeInfo().MatchesWithVariance(toTypeInfo, foundationTypes))
                        return true;
                }
                return false;
            }
            else
            {
                // Interfaces are always castable to System.Object. The code below will not catch this as interfaces report their BaseType as null. 
                if (toTypeInfo.AsType().Equals(foundationTypes.SystemObject) && fromTypeInfo.IsInterface)
                    return true;

                TypeInfo walk = fromTypeInfo;
                for (;;)
                {
                    Type baseType = walk.BaseType;
                    if (baseType == null)
                        return false;
                    walk = baseType.GetTypeInfo();
                    if (walk.MatchesWithVariance(toTypeInfo, foundationTypes))
                        return true;
                }
            }
        }
Esempio n. 9
0
		void SetupPart(TypeInfo sourceType, BindingExpressionPart part)
		{
			part.Arguments = null;
			part.LastGetter = null;
			part.LastSetter = null;

			PropertyInfo property = null;
			if (part.IsIndexer)
			{
				if (sourceType.IsArray)
				{
					int index;
					if (!int.TryParse(part.Content, out index))
						Log.Warning("Binding", "{0} could not be parsed as an index for a {1}", part.Content, sourceType);
					else
						part.Arguments = new object[] { index };

					part.LastGetter = sourceType.GetDeclaredMethod("Get");
					part.LastSetter = sourceType.GetDeclaredMethod("Set");
					part.SetterType = sourceType.GetElementType();
				}

				DefaultMemberAttribute defaultMember = sourceType.GetCustomAttributes(typeof(DefaultMemberAttribute), true).OfType<DefaultMemberAttribute>().FirstOrDefault();
				string indexerName = defaultMember != null ? defaultMember.MemberName : "Item";

				part.IndexerName = indexerName;

				property = sourceType.GetDeclaredProperty(indexerName);
				if (property == null)
					property = sourceType.BaseType.GetProperty(indexerName);

				if (property != null)
				{
					ParameterInfo parameter = property.GetIndexParameters().FirstOrDefault();
					if (parameter != null)
					{
						try
						{
							object arg = Convert.ChangeType(part.Content, parameter.ParameterType, CultureInfo.InvariantCulture);
							part.Arguments = new[] { arg };
						}
						catch (FormatException)
						{
						}
						catch (InvalidCastException)
						{
						}
						catch (OverflowException)
						{
						}
					}
				}
			}
			else
			{
				property = sourceType.GetDeclaredProperty(part.Content);
				if (property == null)
					property = sourceType.BaseType.GetProperty(part.Content);
			}

			if (property != null)
			{
				if (property.CanRead && property.GetMethod.IsPublic && !property.GetMethod.IsStatic)
					part.LastGetter = property.GetMethod;
				if (property.CanWrite && property.SetMethod.IsPublic && !property.SetMethod.IsStatic)
				{
					part.LastSetter = property.SetMethod;
					part.SetterType = part.LastSetter.GetParameters().Last().ParameterType;

					if (Binding.AllowChaining)
					{
						FieldInfo bindablePropertyField = sourceType.GetDeclaredField(part.Content + "Property");
						if (bindablePropertyField != null && bindablePropertyField.FieldType == typeof(BindableProperty) && sourceType.ImplementedInterfaces.Contains(typeof(IElementController)))
						{
							MethodInfo setValueMethod = null;
							foreach (MethodInfo m in sourceType.AsType().GetRuntimeMethods())
							{
								if (m.Name.EndsWith("IElementController.SetValueFromRenderer"))
								{
									ParameterInfo[] parameters = m.GetParameters();
									if (parameters.Length == 2 && parameters[0].ParameterType == typeof(BindableProperty))
									{
										setValueMethod = m;
										break;
									}
								}
							}
							if (setValueMethod != null)
							{
								part.LastSetter = setValueMethod;
								part.IsBindablePropertySetter = true;
								part.BindablePropertyField = bindablePropertyField.GetValue(null);
							}
						}
					}
				}
			}
		}