Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version
Go to top

Resolving Symbolic References in a CodeDOM (Part 7)

, 2 Dec 2012
Resolving symbolic references in a CodeDOM.
Nova.0.6.exe.zip
Mono.Cecil.dll
Nova.CLI.exe
Nova.CodeDOM.dll
Nova.Examples.exe
Nova.Studio.exe
Nova.Test.exe
Nova.UI.dll
Nova.0.6.zip
Nova.CLI
Properties
Nova.CodeDOM
CodeDOM
Annotations
Base
Comments
Base
DocComments
CodeRef
Base
List
Name
Base
Other
Simple
CompilerDirectives
Base
Conditionals
Base
Messages
Base
Pragmas
Base
Symbols
Base
Base
Interfaces
Expressions
AnonymousMethods
Base
Operators
Base
Binary
Arithmetic
Base
Assignment
Base
Bitwise
Base
Conditional
Relational
Base
Shift
Base
Other
Base
Unary
Base
Other
References
Base
GotoTargets
Base
Methods
Namespaces
Other
Properties
Types
Base
Variables
Base
Projects
Assemblies
Namespaces
References
Base
Statements
Base
Conditionals
Base
Exceptions
Generics
Constraints
Base
Iterators
Base
Jumps
Loops
Methods
OperatorDecls
Miscellaneous
Namespaces
Properties
Base
Events
Types
Base
Variables
Base
Parsing
Base
Properties
Rendering
Resolving
Utilities
Mono.Cecil
Reflection
Nova.Examples
Properties
Nova.Studio
Images
About.png
Configuration.png
EditCopy.png
EditCut.png
EditDelete.png
EditPaste.png
EditRedo.png
EditUndo.png
Error.png
Exit.png
FileNew.png
FileOpen.png
FileSave.png
FileSaveAll.png
FileSaveAs.png
Find.png
Help.png
Info.png
Logo.png
Options.png
Print.png
PrintPreview.png
Properties.png
Todo.png
Warning.png
Objects.ico
Properties
Settings.settings
Nova.Test
Properties
Nova.UI
CodeDOM
Annotations
Base
Comments
Base
DocComments
CodeRef
Base
List
Name
Base
Other
Simple
CompilerDirectives
Base
Conditionals
Base
Messages
Base
Pragmas
Base
Symbols
Base
Base
Expressions
AnonymousMethods
Base
Operators
Base
Binary
Arithmetic
Base
Assignment
Base
Bitwise
Base
Conditional
Relational
Base
Shift
Base
Other
Base
Unary
Base
Other
References
Base
GotoTargets
Base
Methods
Namespaces
Other
Properties
Types
Base
Variables
Base
Projects
Namespaces
References
Base
Statements
Base
Conditionals
Base
Exceptions
Generics
Constraints
Base
Iterators
Base
Jumps
Loops
Methods
OperatorDecls
Miscellaneous
Namespaces
Properties
Base
Events
Types
Base
Variables
Base
Properties
Resolving
Utilties
// The Nova Project by Ken Beckett.
// Copyright (C) 2007-2012 Inevitable Software, all rights reserved.
// Released under the Common Development and Distribution License, CDDL-1.0: http://opensource.org/licenses/cddl1.php

using System;
using System.Collections.Generic;
using System.Linq;
using Mono.Cecil;
using Mono.Collections.Generic;

using Nova.Utilities;

namespace Nova.CodeDOM
{
    /// <summary>
    /// Represents a reference to a <see cref="TypeParameter"/> (or <see cref="GenericParameter"/>/<see cref="Type"/>) from <b>within</b>
    /// the generic type or method declaration that declares it.
    /// </summary>
    /// <remarks>
    /// In contrast, an <see cref="OpenTypeParameterRef"/> represents a reference to a <see cref="TypeParameter"/> (or <see cref="GenericParameter"/>
    /// /<see cref="Type"/>) from <b>outside</b> the generic type or method declaration that declares it, and is a temporary placeholder that should
    /// be resolved to either a concrete type or a <see cref="TypeParameterRef"/>.
    /// Like a <see cref="TypeRef"/>, a <see cref="TypeParameterRef"/> can include array ranks.  It subclasses <see cref="TypeRef"/> in order to
    /// provide this functionality, although it doesn't support type arguments.
    /// </remarks>
    public class TypeParameterRef : TypeRef
    {
        #region /* CONSTRUCTORS */

        /// <summary>
        /// Construct a <see cref="TypeParameterRef"/> from a <see cref="TypeParameter"/>.
        /// </summary>
        public TypeParameterRef(TypeParameter declaration, bool isFirstOnLine, List<int> arrayRanks)
            : base(declaration, isFirstOnLine, null, arrayRanks)
        { }

        /// <summary>
        /// Construct a <see cref="TypeParameterRef"/> from a <see cref="TypeParameter"/>.
        /// </summary>
        public TypeParameterRef(TypeParameter declaration, bool isFirstOnLine)
            : base(declaration, isFirstOnLine)
        { }

        /// <summary>
        /// Construct a <see cref="TypeParameterRef"/> from a <see cref="TypeParameter"/>.
        /// </summary>
        public TypeParameterRef(TypeParameter declaration)
            : base(declaration, false)
        { }

        /// <summary>
        /// Construct a <see cref="TypeParameterRef"/> from a <see cref="TypeParameter"/>.
        /// </summary>
        public TypeParameterRef(TypeParameter declaration, List<int> arrayRanks)
            : base(declaration, false, null, arrayRanks)
        { }

        /// <summary>
        /// Construct a <see cref="TypeParameterRef"/> from a <see cref="TypeParameter"/>.
        /// </summary>
        public TypeParameterRef(TypeParameter declaration, bool isFirstOnLine, params int[] arrayRanks)
            : base(declaration, isFirstOnLine, arrayRanks)
        { }

        /// <summary>
        /// Construct a <see cref="TypeParameterRef"/> from a <see cref="TypeParameter"/>.
        /// </summary>
        public TypeParameterRef(TypeParameter declaration, params int[] arrayRanks)
            : base(declaration, false, arrayRanks)
        { }

        /// <summary>
        /// Construct a <see cref="TypeParameterRef"/> from a <see cref="GenericParameter"/>.
        /// </summary>
        public TypeParameterRef(GenericParameter genericParameter, bool isFirstOnLine, List<int> arrayRanks)
            : base(genericParameter, isFirstOnLine, arrayRanks)
        { }

        /// <summary>
        /// Construct a <see cref="TypeParameterRef"/> from a <see cref="GenericParameter"/>.
        /// </summary>
        public TypeParameterRef(GenericParameter genericParameter, bool isFirstOnLine)
            : base(genericParameter, isFirstOnLine)
        { }

        /// <summary>
        /// Construct a <see cref="TypeParameterRef"/> from a <see cref="GenericParameter"/>.
        /// </summary>
        public TypeParameterRef(GenericParameter genericParameter)
            : base(genericParameter, false)
        { }

        /// <summary>
        /// Construct a <see cref="TypeParameterRef"/> from a <see cref="GenericParameter"/>.
        /// </summary>
        public TypeParameterRef(GenericParameter genericParameter, List<int> arrayRanks)
            : base(genericParameter, false, arrayRanks)
        { }

        /// <summary>
        /// Construct a <see cref="TypeParameterRef"/> from a <see cref="GenericParameter"/>.
        /// </summary>
        public TypeParameterRef(GenericParameter genericParameter, bool isFirstOnLine, params int[] arrayRanks)
            : base(genericParameter, isFirstOnLine, arrayRanks)
        { }

        /// <summary>
        /// Construct a <see cref="TypeParameterRef"/> from a <see cref="GenericParameter"/>.
        /// </summary>
        public TypeParameterRef(GenericParameter genericParameter, params int[] arrayRanks)
            : base(genericParameter, false, arrayRanks)
        { }

        /// <summary>
        /// Construct a <see cref="TypeParameterRef"/> from a <see cref="Type"/> (which must be a generic parameter).
        /// </summary>
        public TypeParameterRef(Type type, bool isFirstOnLine, List<int> arrayRanks)
            : base(type, isFirstOnLine, null, arrayRanks)
        { }

        /// <summary>
        /// Construct a <see cref="TypeParameterRef"/> from a <see cref="Type"/> (which must be a generic parameter).
        /// </summary>
        public TypeParameterRef(Type type, bool isFirstOnLine)
            : base(type, isFirstOnLine)
        { }

        /// <summary>
        /// Construct a <see cref="TypeParameterRef"/> from a <see cref="Type"/> (which must be a generic parameter).
        /// </summary>
        public TypeParameterRef(Type type)
            : base(type, false)
        { }

        /// <summary>
        /// Construct a <see cref="TypeParameterRef"/> from a <see cref="Type"/> (which must be a generic parameter).
        /// </summary>
        public TypeParameterRef(Type type, List<int> arrayRanks)
            : base(type, false, null, arrayRanks)
        { }

        /// <summary>
        /// Construct a <see cref="TypeParameterRef"/> from a <see cref="Type"/> (which must be a generic parameter).
        /// </summary>
        public TypeParameterRef(Type type, bool isFirstOnLine, params int[] arrayRanks)
            : base(type, isFirstOnLine, arrayRanks)
        { }

        /// <summary>
        /// Construct a <see cref="TypeParameterRef"/> from a <see cref="Type"/> (which must be a generic parameter).
        /// </summary>
        public TypeParameterRef(Type type, params int[] arrayRanks)
            : base(type, false, arrayRanks)
        { }

        #endregion

        #region /* PROPERTIES */

        /// <summary>
        /// The name of the <see cref="SymbolicRef"/>.
        /// </summary>
        public override string Name
        {
            get
            {
                if (_reference is TypeParameter)
                    return ((TypeParameter)_reference).Name;
                if (_reference is GenericParameter)
                    return ((GenericParameter)_reference).Name;
                return ((Type)_reference).Name;
            }
        }

        /// <summary>
        /// Always <c>false</c>.
        /// </summary>
        public override bool IsDelegateType
        {
            get { return false; }
        }

        /// <summary>
        /// Always <c>true</c>.
        /// </summary>
        public override bool IsPossibleDelegateType
        {
            get { return true; }
        }

        /// <summary>
        /// Always <c>true</c>.
        /// </summary>
        public override bool IsGenericParameter
        {
            get { return true; }
        }

        /// <summary>
        /// True if the referenced type is a value type.
        /// </summary>
        public override bool IsValueType
        {
            get
            {
                // Determine value vs reference type based upon any constraints
                if (_reference is TypeParameter)
                {
                    List<TypeParameterConstraint> constraints = ((TypeParameter)_reference).GetConstraints();
                    if (constraints != null && constraints.Count > 0)
                    {
                        foreach (TypeParameterConstraint constraint in constraints)
                        {
                            if (constraint is ClassConstraint)
                                return false;
                            if (constraint is StructConstraint)
                                return true;
                            if (constraint is TypeConstraint)
                            {
                                TypeRef typeRef = ((TypeConstraint)constraint).EvaluateType() as TypeRef;
                                if (typeRef != null && typeRef.IsValueType)
                                    return true;
                            }
                        }
                    }
                }
                else if (_reference is GenericParameter)
                {
                    GenericParameterAttributes attributes = ((GenericParameter)_reference).Attributes;
                    if (attributes.HasFlag(GenericParameterAttributes.ReferenceTypeConstraint))  // class constraint
                        return false;
                    if (attributes.HasFlag(GenericParameterAttributes.NotNullableValueTypeConstraint))  // struct constraint
                        return true;
                    Collection<TypeReference> constraintTypes = ((GenericParameter)_reference).Constraints;
                    if (constraintTypes != null && constraintTypes.Count > 0)
                        return Enumerable.Any(constraintTypes, delegate(TypeReference constraintType) { return constraintType.IsValueType; });
                }
                else //if (_reference is Type)
                {
                    System.Reflection.GenericParameterAttributes attributes = ((Type)_reference).GenericParameterAttributes;
                    if (attributes.HasFlag(System.Reflection.GenericParameterAttributes.ReferenceTypeConstraint))  // class constraint
                        return false;
                    if (attributes.HasFlag(System.Reflection.GenericParameterAttributes.NotNullableValueTypeConstraint))  // struct constraint
                        return true;
                    Type[] constraints = ((Type)_reference).GetGenericParameterConstraints();
                    if (constraints.Length > 0)
                        return Enumerable.Any(constraints, delegate(Type constraintType) { return constraintType.IsValueType; });
                }
                return false;
            }
        }

        /// <summary>
        /// Always <c>false</c>.
        /// </summary>
        public override bool IsConst
        {
            get { return false; }
        }

        /// <summary>
        /// The type argument <see cref="Expression"/>s of the reference (if any).
        /// </summary>
        public override ChildList<Expression> TypeArguments
        {
            get { return null; }
            set
            {
                if (value != null)
                    throw new Exception("Can't set type arguments on a TypeParameterRef!");
            }
        }

        #endregion

        #region /* METHODS */

        /// <summary>
        /// Determine if the current reference refers to the same code object as the specified reference.
        /// </summary>
        public override bool IsSameRef(SymbolicRef symbolicRef)
        {
            if (!(symbolicRef is TypeParameterRef))
                return false;

            TypeParameterRef typeParameterRef = (TypeParameterRef)symbolicRef;
            object reference = GetReferencedType();
            object typeParameterRefReference = typeParameterRef.GetReferencedType();

            if (reference != typeParameterRefReference)
            {
                // We also have to consider the references the same if the Name and NamespaceNames match.
                // This can occur when types are present both in an assembly reference, and also as CodeDOM
                // objects (either in the current project, or a referenced project).  This can occur if one
                // or both types are in a project with assembly references instead of project references to
                // a type that is defined in the current solution, which isn't uncommon - it will occur in
                // "master" solutions that include projects that are also used in other solutions, and also
                // if a project in the solution uses a non-supported language and so is referenced by its
                // assembly.
                if (Name != typeParameterRef.Name || NamespaceName != typeParameterRef.NamespaceName)
                    return false;

                // With type parameters, the declaring (parent) type names must also match for the type
                // parameters to be considered the same.
                string declaringTypeName = GetDeclaringTypeOrMethodName(reference);
                string typeParameterRefDeclaringTypeName = typeParameterRef.GetDeclaringTypeOrMethodName();
                if (declaringTypeName == null || typeParameterRefDeclaringTypeName == null
                    || declaringTypeName != typeParameterRefDeclaringTypeName)
                    return false;
            }

            return HasSameArrayRanks(typeParameterRef);
        }

        /// <summary>
        /// Calculate a hash code for the referenced object which is the same for all references where IsSameRef() is true.
        /// </summary>
        public override int GetIsSameRefHashCode()
        {
            // Make the hash codes as unique as possible while still ensuring that they are identical
            // for any objects for which IsSameRef() returns true.
            int hashCode = Name.GetHashCode();
            string namespaceName = NamespaceName;
            if (namespaceName != null) hashCode ^= namespaceName.GetHashCode();
            if (_arrayRanks != null)
            {
                foreach (int rank in _arrayRanks)
                    hashCode = (hashCode << 1) ^ rank;
            }
            return hashCode;
        }

        /// <summary>
        /// Get the actual type reference (TypeParameter or Type).
        /// </summary>
        /// <returns>The TypeParameter or Type.</returns>
        public override object GetReferencedType()
        {
            return Reference;
        }

        /// <summary>
        /// Get the declaring generic type or method.
        /// </summary>
        public TypeRefBase GetDeclaringTypeOrMethod()
        {
            object reference = GetReferencedType();
            if (reference is TypeParameter)
            {
                CodeObject parent = ((TypeParameter)reference).Parent;
                if (parent is GenericMethodDecl)
                {
                    GenericMethodDecl methodDecl = (GenericMethodDecl)parent;
                    return methodDecl.CreateRef(ChildList<Expression>.CreateListOfNulls(methodDecl.TypeParameterCount));
                }
                if (parent is ITypeDecl)
                {
                    ITypeDecl typeDecl = (ITypeDecl)parent;
                    return typeDecl.CreateRef(ChildList<Expression>.CreateListOfNulls(typeDecl.TypeParameterCount));
                }
            }
            else if (reference is GenericParameter)
            {
                GenericParameter genericParameter = (GenericParameter)reference;
                IGenericParameterProvider owner = genericParameter.Owner;
                if (owner is MethodReference)
                    return MethodRef.Create((MethodReference)owner);
                return Create((TypeReference)owner);
            }
            else if (reference is Type)
            {
                Type typeParameter = (Type)reference;
                if (typeParameter.DeclaringMethod != null)
                    return MethodRef.Create(typeParameter.DeclaringMethod);
                Type declaringType = ((Type)reference).DeclaringType;
                return (declaringType != null ? Create(declaringType) : null);
            }
            return null;
        }

        /// <summary>
        /// Get the declaring generic type (returns null if the parent is a method).
        /// </summary>
        public override TypeRefBase GetDeclaringType()
        {
            return GetDeclaringTypeOrMethod() as TypeRef;
        }

        /// <summary>
        /// Get the name of the declaring generic type or method.
        /// </summary>
        public string GetDeclaringTypeOrMethodName()
        {
            return GetDeclaringTypeOrMethodName(GetReferencedType());
        }

        /// <summary>
        /// Get the name of the declaring generic type or method for the specified type parameter
        /// (<see cref="TypeParameter"/> or <see cref="Type"/>).
        /// </summary>
        protected static string GetDeclaringTypeOrMethodName(object reference)
        {
            if (reference is TypeParameter)
            {
                CodeObject parent = ((TypeParameter)reference).Parent;
                if (parent is INamedCodeObject)
                    return ((INamedCodeObject)parent).Name;
            }
            else if (reference is GenericParameter)
            {
                GenericParameter genericParameter = (GenericParameter)reference;
                IGenericParameterProvider owner = genericParameter.Owner;
                if (owner is MethodReference)
                    return ((MethodReference)owner).Name;
                return ((TypeReference)owner).Name;
            }
            else if (reference is Type)
            {
                Type typeParameter = (Type)reference;
                if (typeParameter.DeclaringMethod != null)
                    return typeParameter.DeclaringMethod.Name;
                if (typeParameter.DeclaringType != null)
                    return typeParameter.DeclaringType.Name;
            }
            return null;
        }

        /// <summary>
        /// Get the type constraints (if any) for this type parameter.
        /// </summary>
        public List<TypeRefBase> GetTypeConstraints()
        {
            List<TypeRefBase> constraintTypeRefs = null;
            if (_reference is TypeParameter)
            {
                List<TypeParameterConstraint> constraints = ((TypeParameter)_reference).GetConstraints();
                if (constraints != null)
                {
                    foreach (TypeParameterConstraint constraint in constraints)
                    {
                        if (constraint is TypeConstraint)
                        {
                            if (constraintTypeRefs == null)
                                constraintTypeRefs = new List<TypeRefBase>();
                            constraintTypeRefs.Add(((TypeConstraint)constraint).EvaluateType());
                        }
                    }
                }
            }
            else if (_reference is GenericParameter)
            {
                Collection<TypeReference> constraintTypes = ((GenericParameter)_reference).Constraints;
                if (constraintTypes != null && constraintTypes.Count > 0)
                {
                    constraintTypeRefs = new List<TypeRefBase>();
                    foreach (TypeReference typeConstraint in constraintTypes)
                        constraintTypeRefs.Add(Create(typeConstraint));
                }
            }
            else //if (_reference is Type)
            {
                Type[] constraintTypes = ((Type)_reference).GetGenericParameterConstraints();
                if (constraintTypes.Length > 0)
                {
                    constraintTypeRefs = new List<TypeRefBase>();
                    foreach (Type typeConstraint in constraintTypes)
                        constraintTypeRefs.Add(Create(typeConstraint));
                }
            }
            return constraintTypeRefs;
        }

        #endregion

        #region /* RESOLVING */

        /// <summary>
        /// Evaluate the type of the <see cref="TypeParameter"/> by searching for matching type arguments in the
        /// specified parent code object tree.
        /// </summary>
        public override TypeRefBase EvaluateTypeArgumentTypes(CodeObject parent, CodeObject originatingChild)
        {
            TypeRefBase result;

            // If this TypeParameterRef is part of an explicit inteface implementation, leave it alone so that it won't
            // be converted to an OpenTypeParameterRef and left as one.
            if (parent is Dot && ((Dot)parent).Right == originatingChild && parent.Parent is GenericMethodDecl && ((GenericMethodDecl)parent.Parent).ExplicitInterfaceExpression == parent)
                result = this;
            else
            {
                // In most cases, when a TypeParameterRef is evaluated, we have to convert it back to an OpenTypeParameterRef and re-evaluate it,
                // because its context might have changed from inside a generic type definition to a concrete instance of the generic type (for
                // example, the type of a field or return type of a method changes when it's referenced in the context of an instance of the type).
                // If the reference is a Type, then it's an external TypeParameter and can't be in scope, so it must always be evaluated.
                object reference = Reference;
                if (reference is TypeParameter)
                    result = new OpenTypeParameterRef((TypeParameter)reference, IsFirstOnLine, ArrayRanks).EvaluateTypeArgumentTypes(parent, originatingChild);
                else if (reference is GenericParameter)
                    result = new OpenTypeParameterRef((GenericParameter)reference, IsFirstOnLine, ArrayRanks).EvaluateTypeArgumentTypes(parent, originatingChild);
                else //if (reference is Type)
                    result = new OpenTypeParameterRef((Type)reference, IsFirstOnLine, ArrayRanks).EvaluateTypeArgumentTypes(parent, originatingChild);
            }
            return result;
        }

        /// <summary>
        /// Find a type argument for the specified type parameter.
        /// </summary>
        public override TypeRefBase FindTypeArgument(TypeParameterRef typeParameterRef, CodeObject originatingChild)
        {
            // Look for the type argument in any type constraints
            if (_reference is TypeParameter)
                return ((TypeParameter)_reference).FindTypeArgument(typeParameterRef);

            if (_reference is GenericParameter)
            {
                TypeReference typeReference = null;
                GenericParameter genericParameter = typeParameterRef.Reference as GenericParameter;
                if (genericParameter != null)
                {
                    foreach (TypeReference constraintType in ((GenericParameter)_reference).Constraints)
                    {
                        typeReference = TypeDefinitionUtil.FindTypeArgument(constraintType, genericParameter);
                        if (typeReference != null)
                            break;
                    }
                }
                return Create(typeReference);
            }

            Type type = null;
            Type typeParameter = typeParameterRef.Reference as Type;
            if (typeParameter != null)
            {
                foreach (Type constraintType in ((Type)_reference).GetGenericParameterConstraints())
                {
                    type = TypeUtil.FindTypeArgument(constraintType, typeParameter);
                    if (type != null)
                        break;
                }
            }
            return Create(type);
        }

        /// <summary>
        /// Determine if the <see cref="TypeParameterRef"/> is implicitly convertible to the specified <see cref="TypeRefBase"/>.
        /// </summary>
        /// <param name="toTypeRefBase">The <see cref="TypeRef"/>, <see cref="MethodRef"/>, or <see cref="UnresolvedRef"/> being checked.</param>
        /// <param name="standardConversionsOnly">True if only standard conversions should be allowed.</param>
        public override bool IsImplicitlyConvertibleTo(TypeRefBase toTypeRefBase, bool standardConversionsOnly)
        {
            // Implicit conversions involving type parameters
            // The following implicit conversions exist for a given type parameter T:
            // - From T to its effective base class C, from T to any base class of C, and from T to any interface implemented by C.
            //   At run-time, if T is a value type, the conversion is executed as a boxing conversion. Otherwise, the conversion is
            //   executed as an implicit reference conversion or identity conversion.
            // - From T to an interface type I in T’s effective interface set and from T to any base interface of I. At run-time,
            //   if T is a value type, the conversion is executed as a boxing conversion. Otherwise, the conversion is executed as
            //   an implicit reference conversion or identity conversion.
            // - From T to a type parameter U, provided T depends on U. At run-time, if U is a value type, then T and U are
            //   necessarily the same type and no conversion is performed. Otherwise, if T is a value type, the conversion is executed
            //   as a boxing conversion. Otherwise, the conversion is executed as an implicit reference conversion or identity conversion.
            // - From the null literal to T, provided T is known to be a reference type. (See Literal.IsImplicitlyConvertibleTo())
            // If T is known to be a reference type, the conversions above are all classified as implicit reference
            // conversions. If T is not known to be a reference type, the conversions described in the first two bullets
            // above are classified as boxing conversions.

            return IsImplicitlyConvertible(toTypeRefBase, false);
        }

        /// <summary>
        /// Determine if the reference is implicitly convertible *from* the specified reference.
        /// </summary>
        public override bool IsImplicitlyConvertibleFrom(TypeRefBase fromTypeRefBase)
        {
            return IsImplicitlyConvertible(fromTypeRefBase, true);
        }

        /// <summary>
        /// Determine if the reference is implicitly convertible to the specified reference.
        /// </summary>
        protected bool IsImplicitlyConvertible(TypeRefBase toTypeRefBase, bool reverse)
        {
            // Implicit identity conversion
            if (IsSameRef(toTypeRefBase))
                return true;

            // Check for implicit conversion to certain constraints
            if (_reference is TypeParameter)
            {
                List<TypeParameterConstraint> constraints = ((TypeParameter)_reference).GetConstraints();
                if (constraints != null && constraints.Count > 0)
                {
                    foreach (TypeParameterConstraint constraint in constraints)
                    {
                        TypeRefBase fromTypeRefBase = null;
                        if (constraint is TypeConstraint)
                            fromTypeRefBase = ((TypeConstraint)constraint).EvaluateType();
                        else if (constraint is ClassConstraint)
                            fromTypeRefBase = ObjectRef;
                        else if (constraint is StructConstraint)
                            fromTypeRefBase = ValueTypeRef;
                        if (fromTypeRefBase != null && IsImplicitlyConvertible(fromTypeRefBase, toTypeRefBase, reverse))
                            return true;
                    }
                }
            }
            else if (_reference is GenericParameter)
            {
                if (toTypeRefBase is UnresolvedRef)
                    return false;

                Collection<TypeReference> constraints = ((GenericParameter)_reference).Constraints;
                if (constraints != null && constraints.Count > 0)
                {
                    if (Enumerable.Any(constraints, delegate(TypeReference typeReference) { return IsImplicitlyConvertible(Create(typeReference), toTypeRefBase, reverse); }))
                        return true;

                    TypeRef fromTypeRef = null;
                    GenericParameterAttributes attributes = ((GenericParameter)_reference).Attributes;
                    if (attributes.HasFlag(GenericParameterAttributes.ReferenceTypeConstraint))  // class constraint
                        fromTypeRef = ObjectRef;
                    else if (attributes.HasFlag(GenericParameterAttributes.NotNullableValueTypeConstraint))  // struct constraint
                        fromTypeRef = ValueTypeRef;
                    if (fromTypeRef != null && IsImplicitlyConvertible(fromTypeRef, toTypeRefBase, reverse))
                        return true;
                }
            }
            else //if (_reference is Type)
            {
                if (toTypeRefBase is UnresolvedRef)
                    return false;

                Type[] constraints = ((Type)_reference).GetGenericParameterConstraints();
                if (constraints.Length > 0)
                {
                    if (Enumerable.Any(constraints, delegate(Type type) { return IsImplicitlyConvertible(Create(type), toTypeRefBase, reverse); }))
                        return true;

                    TypeRef fromTypeRef = null;
                    System.Reflection.GenericParameterAttributes attributes = ((Type)_reference).GenericParameterAttributes;
                    if (attributes.HasFlag(System.Reflection.GenericParameterAttributes.ReferenceTypeConstraint))  // class constraint
                        fromTypeRef = ObjectRef;
                    else if (attributes.HasFlag(System.Reflection.GenericParameterAttributes.NotNullableValueTypeConstraint))  // struct constraint
                        fromTypeRef = ValueTypeRef;
                    if (fromTypeRef != null && IsImplicitlyConvertible(fromTypeRef, toTypeRefBase, reverse))
                        return true;
                }
            }

            // Also check for conversion from 'object'
            return IsImplicitlyConvertible(ObjectRef, toTypeRefBase, reverse);
        }

        /// <summary>
        /// Determine if the specified 'from' reference is implicitly convertible to the specified 'to' reference.
        /// </summary>
        protected bool IsImplicitlyConvertible(TypeRefBase fromTypeRefBase, TypeRefBase toTypeRefBase, bool reverse)
        {
            if (fromTypeRefBase != null)
            {
                // First, add back any lost array ranks to 'fromTypeRefBase' (done here so that all callers
                // of this method don't have to do it).
                if (IsArray)
                    fromTypeRefBase = fromTypeRefBase.MakeArrayRef(ArrayRanks);

                if (reverse)
                {
                    if (fromTypeRefBase.IsImplicitlyConvertibleFrom(toTypeRefBase))
                        return true;
                }
                else
                {
                    if (fromTypeRefBase.IsImplicitlyConvertibleTo(toTypeRefBase))
                        return true;
                }
            }
            return false;
        }

        #endregion
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Common Development and Distribution License (CDDL)

Share

About the Author

KenBeckett
Software Developer (Senior)
United States United States
I've been writing software since the late 70's, currently focusing mainly on C#.NET. I also like to travel around the world, and I own a Chocolate Factory (sadly, none of my employees are oompa loompas).

| Advertise | Privacy | Mobile
Web04 | 2.8.140926.1 | Last Updated 2 Dec 2012
Article Copyright 2012 by KenBeckett
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid