/// <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); } }
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; }
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 ('&'); }
// 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; }
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; } } }