Click here to Skip to main content
15,884,472 members
Articles / Programming Languages / C#

Calculating Metrics and Searching with a CodeDOM (Part 8)

Rate me:
Please Sign up or sign in to vote.
5.00/5 (7 votes)
6 Mar 2013CDDL7 min read 22K   682   10  
Calculating metrics on and searching a CodeDOM.
// 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.Reflection;

namespace Nova.Utilities
{
    /// <summary>
    /// Static helper methods for <see cref="Type"/>.
    /// </summary>
    public static class TypeUtil
    {
        #region /* STATIC HELPER METHODS */

        /// <summary>
        /// Returns the name without any trailing '`' and type parameter count.
        /// </summary>
        public static string NonGenericName(Type thisType)
        {
            // The names of generic types have a trailing "`" followed by the number of type arguments that they
            // have (generic methods do NOT).  However, the type argument count only includes those arguments at
            // the current level, and not any arguments of enclosing types, even though calling GetGenericArguments()
            // will return all type arguments from all levels.  If a nested type has one or more generic types
            // enclosing it, then it's considered a generic type even if it doesn't have any type parameters of
            // its own (IsGenericType will be true, and GetGenericArguments() will return the type arguments of
            // its enclosing generic types), however its name won't have the "`" suffix.
            string name = thisType.Name;
            int index = name.LastIndexOf('`');
            return (index >= 0 ? name.Substring(0, index) : name);
        }

        /// <summary>
        /// Return true if the type is static, otherwise false.
        /// </summary>
        public static bool IsStatic(Type thisType)
        {
            return (thisType.IsAbstract && thisType.IsSealed);
        }

        /// <summary>
        /// Return true if the type is private, otherwise false.
        /// </summary>
        public static bool IsPrivate(Type thisType)
        {
            return (thisType.IsNested && thisType.IsNestedPrivate);
        }

        /// <summary>
        /// Return true if the type is protected, otherwise false.
        /// </summary>
        public static bool IsProtected(Type thisType)
        {
            return (thisType.IsNested && thisType.IsNestedFamily);
        }

        /// <summary>
        /// Return true if the type is internal, otherwise false.
        /// </summary>
        public static bool IsInternal(Type thisType)
        {
            return (thisType.IsNested ? thisType.IsNestedAssembly : thisType.IsNotPublic);
        }

        /// <summary>
        /// Determine if the type is a user-defined class (excludes 'object' and 'string').
        /// </summary>
        public static bool IsUserClass(Type thisType)
        {
            // Exclude built-in types that are classes (object and string)
            return (thisType.IsClass && thisType != typeof(object) && thisType != typeof(string));
        }

        /// <summary>
        /// Determine if the type is a user-defined struct (excludes primitive types including 'void' and 'decimal', and enums).
        /// </summary>
        public static bool IsUserStruct(Type thisType)
        {
            // Exclude primitive types, enums, and built-in types that are value types but aren't primitive (void and decimal)
            return (thisType.IsValueType && !thisType.IsPrimitive && !thisType.IsEnum && thisType != typeof(void) && thisType != typeof(decimal));
        }

        /// <summary>
        /// Determine if the type is a nullable type.
        /// </summary>
        public static bool IsNullableType(Type thisType)
        {
            return (thisType.IsGenericType && thisType.GetGenericTypeDefinition() == typeof(Nullable<>) && !thisType.IsGenericTypeDefinition);
        }

        /// <summary>
        /// Determine if the type is a delegate type.
        /// </summary>
        public static bool IsDelegateType(Type thisType)
        {
            return typeof(Delegate).IsAssignableFrom(thisType);
        }

        /// <summary>
        /// The name of the flags attribute.
        /// </summary>
        public const string FlagsAttributeName = "FlagsAttribute";

        /// <summary>
        /// Determine if the type is a bit-flags style enum.
        /// </summary>
        public static bool IsBitFlagsEnum(Type thisType)
        {
            return MemberInfoUtil.HasCustomAttribute(thisType, FlagsAttributeName);
        }

        /// <summary>
        /// Determine if the type implements the specified interface.  If a generic interface is specified, and
        /// it's not the generic type definition of the interface, then the type arguments are also compared.
        /// </summary>
        public static bool IsImplementationOf(Type thisType, Type interfaceType)
        {
            if (interfaceType.IsGenericType)
            {
                if (interfaceType.IsGenericTypeDefinition)
                {
                    // If the specified interface is a generic type definition, then match on generic type definitions
                    foreach (Type @interface in thisType.GetInterfaces())
                    {
                        if (@interface.IsGenericType && @interface.GetGenericTypeDefinition() == interfaceType)
                            return true;
                    }
                }
                else
                {
                    // If the specified interface isn't a generic type definition, then also match on any type arguments
                    foreach (Type @interface in thisType.GetInterfaces())
                    {
                        if (@interface.IsGenericType && @interface == interfaceType && HasSameTypeArguments(@interface, interfaceType))
                            return true;
                    }
                }
            }
            else
            {
                // Handle non-generic interfaces
                foreach (Type @interface in thisType.GetInterfaces())
                {
                    if (@interface == interfaceType)
                        return true;
                }
            }
            return false;
        }

        /// <summary>
        /// Make an array type.
        /// </summary>
        public static Type MakeArrayType(Type thisType, List<int> arrayRanks)
        {
            Type type = thisType;
            foreach (int dim in arrayRanks)
                type = type.MakeArrayType(dim);
            return type;
        }

        /// <summary>
        /// Get the parameters for a delegate type.
        /// </summary>
        public static ParameterInfo[] GetDelegateParameters(Type thisType)
        {
            MethodInfo methodInfo = GetInvokeMethod(thisType);
            return (methodInfo != null ? methodInfo.GetParameters() : null);
        }

        /// <summary>
        /// Get the return type for a delegate type.
        /// </summary>
        public static Type GetDelegateReturnType(Type thisType)
        {
            MethodInfo methodInfo = GetInvokeMethod(thisType);
            return (methodInfo != null ? methodInfo.ReturnType : null);
        }

        /// <summary>
        /// Get the 'Invoke()' method for the specified <see cref="Type"/>.
        /// </summary>
        public static MethodInfo GetInvokeMethod(Type type)
        {
            // As a workaround for a possible fix in one of the TypeRef constructors that we haven't activated
            // because it breaks other things, make certain that we're using the generic type definition, so
            // that any type parameters in the method signature reflect the ones from the definition as opposed
            // to those from a parent generic type or method.
            if (type.IsGenericType && !type.IsGenericTypeDefinition)
                type = type.GetGenericTypeDefinition();
            return type.GetMethod("Invoke");
        }

        /// <summary>
        /// Get the number of local generic arguments for the type, NOT including arguments from any enclosing generic types.
        /// </summary>
        public static int GetLocalGenericArgumentCount(Type thisType)
        {
            int count = thisType.GetGenericArguments().Length;
            if (count > 0 && thisType.IsNested)
            {
                Type declaringType = thisType.DeclaringType;
                if (declaringType != null)
                    count -= declaringType.GetGenericArguments().Length;
            }
            return count;
        }

        /// <summary>
        /// Get the local generic arguments for the type, NOT including arguments from any enclosing generic types.
        /// </summary>
        public static Type[] GetLocalGenericArguments(Type thisType)
        {
            Type[] totalArguments = thisType.GetGenericArguments();
            int totalCount = totalArguments.Length;
            if (totalCount == 0 || !thisType.IsNested)
                return totalArguments;

            int localCount = GetLocalGenericArgumentCount(thisType);
            if (localCount == totalCount)
                return totalArguments;

            Type[] localArguments = new Type[localCount];
            if (localCount > 0)
                Array.Copy(totalArguments, totalCount - localCount, localArguments, 0, localCount);
            return localArguments;
        }

        /// <summary>
        /// Determine if this type has the same type arguments as the specified type.
        /// </summary>
        public static bool HasSameTypeArguments(Type thisType, Type type)
        {
            Type[] thisArguments = thisType.GetGenericArguments();
            Type[] arguments = type.GetGenericArguments();
            if (thisArguments.Length != arguments.Length)
                return false;
            for (int i = 0; i < thisArguments.Length; ++i)
            {
                if (thisArguments[i] != arguments[i])
                    return false;
            }
            return true;
        }

        /// <summary>
        /// Special type used to match any generic parameter type in GetMethodExt().
        /// </summary>
        public class T
        {
        }

        /// <summary>
        /// Search for a method by name and parameter types.  Unlike GetMethod(), does 'loose' matching on generic
        /// parameter types, and searches base interfaces.
        /// </summary>
        /// <exception cref="AmbiguousMatchException"/>
        public static MethodInfo GetMethod(Type thisType, string name, params Type[] parameterTypes)
        {
            return GetMethod(thisType, name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy, parameterTypes);
        }

        /// <summary>
        /// Search for a method by name, parameter types, and binding flags.  Unlike GetMethod(), does 'loose' matching on generic
        /// parameter types, and searches base interfaces.
        /// </summary>
        /// <exception cref="AmbiguousMatchException"/>
        public static MethodInfo GetMethod(Type thisType, string name, BindingFlags bindingFlags, params Type[] parameterTypes)
        {
            MethodInfo matchingMethod = null;

            // Check all methods with the specified name, including in base classes
            GetMethod(ref matchingMethod, thisType, name, bindingFlags, parameterTypes);

            // If we're searching an interface, we have to manually search base interfaces
            if (matchingMethod == null && thisType.IsInterface)
            {
                foreach (Type interfaceType in thisType.GetInterfaces())
                    GetMethod(ref matchingMethod, interfaceType, name, bindingFlags, parameterTypes);
            }

            return matchingMethod;
        }

        private static void GetMethod(ref MethodInfo matchingMethod, Type type, string name, BindingFlags bindingFlags, params Type[] parameterTypes)
        {
            // Check all methods with the specified name, including in base classes if BindingFlags.FlattenHierarchy is specified
            foreach (MethodInfo methodInfo in type.GetMember(name, MemberTypes.Method, bindingFlags))
            {
                // Check that the parameter counts and types match, with 'loose' matching on generic parameters
                ParameterInfo[] parameterInfos = methodInfo.GetParameters();
                if (parameterInfos.Length == parameterTypes.Length)
                {
                    int i = 0;
                    for (; i < parameterInfos.Length; ++i)
                    {
                        if (!IsSimilarType(parameterInfos[i].ParameterType, parameterTypes[i]))
                            break;
                    }
                    if (i == parameterInfos.Length)
                    {
                        if (matchingMethod == null)
                        {
                            matchingMethod = methodInfo;
                            return;
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Search for a property by name.  Unlike GetProperty(), searches base interfaces.
        /// </summary>
        /// <exception cref="AmbiguousMatchException"/>
        public static PropertyInfo GetProperty(Type thisType, string name)
        {
            PropertyInfo matchingProperty = thisType.GetProperty(name);

            // If we're searching an interface, we have to manually search base interfaces
            if (matchingProperty == null && thisType.IsInterface)
            {
                foreach (Type interfaceType in thisType.GetInterfaces())
                {
                    matchingProperty = interfaceType.GetProperty(name);
                    if (matchingProperty != null)
                        break;
                }
            }

            return matchingProperty;
        }

        /// <summary>
        /// Determines if the two types are either identical, or are both generic parameters or generic types
        /// with generic parameters in the same locations (generic parameters match any other generic parameter,
        /// but NOT concrete types).
        /// </summary>
        private static bool IsSimilarType(Type thisType, Type type)
        {
            // Ignore any 'ref' types
            if (thisType.IsByRef)
                thisType = thisType.GetElementType();
            if (type.IsByRef)
                type = type.GetElementType();

            // Handle array types
            if (thisType.IsArray && type.IsArray)
                return IsSimilarType(thisType.GetElementType(), type.GetElementType());

            // If the types are identical, or the names/namespaces match (they could be defined in separate assemblies), or
            // if they're both generic parameters or the special 'T' type, treat as a match.
            if (thisType == type || (thisType.Name == type.Name && thisType.Namespace == type.Namespace)
                || ((thisType.IsGenericParameter || thisType == typeof(T)) && (type.IsGenericParameter || type == typeof(T))))
                return true;

            // Handle any generic arguments
            if (thisType.IsGenericType && type.IsGenericType)
            {
                Type[] thisArguments = thisType.GetGenericArguments();
                Type[] arguments = type.GetGenericArguments();
                if (thisArguments.Length == arguments.Length)
                {
                    for (int i = 0; i < thisArguments.Length; ++i)
                    {
                        if (!IsSimilarType(thisArguments[i], arguments[i]))
                            return false;
                    }
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        /// Find a type argument for the specified type parameter.
        /// </summary>
        public static Type FindTypeArgument(Type thisType, Type typeParameter)
        {
            if (thisType.IsGenericType)
            {
                foreach (Type genericParameter in thisType.GetGenericTypeDefinition().GetGenericArguments())
                {
                    if (genericParameter == typeParameter)
                        return thisType.GetGenericArguments()[genericParameter.GenericParameterPosition];
                }
            }

            // If we didn't find a match, search any base types
            return FindTypeArgumentInBase(thisType, typeParameter);
        }

        /// <summary>
        /// Find the index of the specified type parameter.
        /// </summary>
        public static int FindTypeParameterIndex(Type thisType, Type typeParameter)
        {
            if (thisType != null && thisType.IsGenericType && typeParameter != null)
            {
                // If the TypeParameter is declared in a nested type that isn't 'thisType', move up through it's enclosing
                // types looking for a matching type, and update the TypeParameter if we find one.
                Type declaringType = typeParameter.DeclaringType;
                while (declaringType != null && declaringType.IsGenericType)
                {
                    if (declaringType == thisType || declaringType.GetGenericTypeDefinition() == thisType.GetGenericTypeDefinition())
                    {
                        if (declaringType != typeParameter.DeclaringType)
                        {
                            // If we moved up to a enclosing type, update the TypeParameter to the one declared there if possible
                            Type[] genericArguments = declaringType.GetGenericArguments();
                            if (typeParameter.GenericParameterPosition < genericArguments.Length)
                                typeParameter = genericArguments[typeParameter.GenericParameterPosition];
                        }
                        break;
                    }
                    declaringType = declaringType.DeclaringType;
                }

                // If TypeParameter isn't found in 'thisType' and it's nested, move up through it's enclosing types, searching them also
                Type currentType = thisType;
                do
                {
                    // Search the generic type definition first, but if the type isn't the definition and we don't find a match in the
                    // definition, then also search the type itself.  This is necessary because if one generic type references another
                    // in it's definition, the referenced generic type will have type parameters of the "parent" generic type and we
                    // can match on those - avoiding extra work of searching until we find the parent generic type instance.  It's also
                    // important to NOT check that 'currentType' matches 'declaringType' here for this reason, AND we can't just look
                    // at the TypeParameter's position, but must scan all of the type arguments.
                    if (!currentType.IsGenericTypeDefinition)
                    {
                        foreach (Type genericParameter in thisType.GetGenericTypeDefinition().GetGenericArguments())
                        {
                            if (genericParameter == typeParameter)
                                return genericParameter.GenericParameterPosition;
                        }
                    }
                    // In this case, we can't use GenericParameterPosition, because we're not necessarily using the GenericTypeDefinition,
                    // so the position might refer to the position within the declaring type, which might not be the same as 'thisType'.
                    Type[] genericArguments = thisType.GetGenericArguments();
                    for (int i = 0; i < genericArguments.Length; ++i)
                    {
                        if (genericArguments[i] == typeParameter)
                            return i;
                    }

                    currentType = currentType.DeclaringType;
                }
                while (currentType != null && currentType.IsGenericType);
            }
            return -1;
        }

        /// <summary>
        /// Find a type argument in a base class for the specified type parameter.
        /// </summary>
        public static Type FindTypeArgumentInBase(Type thisType, Type typeParameter)
        {
            Type found = null;
            Type baseType = thisType.BaseType;
            if (baseType != null && baseType != typeof(object))
                found = FindTypeArgument(baseType, typeParameter);
            if (found != null) return found;
            Type[] interfaces = thisType.GetInterfaces();
            foreach (Type @interface in interfaces)
            {
                found = FindTypeArgument(@interface, typeParameter);
                if (found != null) return found;
            }
            return null;
        }

        /// <summary>
        /// Change the specified object to the specified type, forcing larger integers into smaller ones without exceptions.
        /// </summary>
        public static object ChangeType(object obj, Type toType)
        {
            if (obj == null || toType == null)
                return null;

            object newObj = null;
            try
            {
                // Tragically, the Convert.ChangeType() method can't be used to explicitly convert from larger to smaller
                // types (it will throw an exception and fail).  Therefore, we do explicit conversions here for any that
                // might otherwise throw exceptions, and use Convert.ChangeType() for all others.  Very ugly, but it works.
                TypeCode toTypeCode = Type.GetTypeCode(toType);
                TypeCode fromTypeCode = Type.GetTypeCode(obj.GetType());
                switch (toTypeCode)
                {
                    case TypeCode.Byte:
                        switch (fromTypeCode)
                        {
                            case TypeCode.Byte:
                                newObj = obj;
                                break;
                            case TypeCode.SByte:
                                newObj = (byte)(sbyte)obj;
                                break;
                            case TypeCode.Int16:
                                newObj = (byte)(short)obj;
                                break;
                            case TypeCode.UInt16:
                                newObj = (byte)(ushort)obj;
                                break;
                            case TypeCode.Int32:
                                newObj = (byte)(int)obj;
                                break;
                            case TypeCode.UInt32:
                                newObj = (byte)(uint)obj;
                                break;
                            case TypeCode.Int64:
                                newObj = (byte)(long)obj;
                                break;
                            case TypeCode.UInt64:
                                newObj = (byte)(ulong)obj;
                                break;
                            case TypeCode.Single:
                                newObj = (byte)(float)obj;
                                break;
                            case TypeCode.Double:
                                newObj = (byte)(double)obj;
                                break;
                            case TypeCode.Decimal:
                                newObj = (byte)(decimal)obj;
                                break;
                        }
                        break;
                    case TypeCode.SByte:
                        switch (fromTypeCode)
                        {
                            case TypeCode.Byte:
                                newObj = (sbyte)(byte)obj;
                                break;
                            case TypeCode.SByte:
                                newObj = obj;
                                break;
                            case TypeCode.Int16:
                                newObj = (sbyte)(short)obj;
                                break;
                            case TypeCode.UInt16:
                                newObj = (sbyte)(ushort)obj;
                                break;
                            case TypeCode.Int32:
                                newObj = (sbyte)(int)obj;
                                break;
                            case TypeCode.UInt32:
                                newObj = (sbyte)(uint)obj;
                                break;
                            case TypeCode.Int64:
                                newObj = (sbyte)(long)obj;
                                break;
                            case TypeCode.UInt64:
                                newObj = (sbyte)(ulong)obj;
                                break;
                            case TypeCode.Single:
                                newObj = (sbyte)(float)obj;
                                break;
                            case TypeCode.Double:
                                newObj = (sbyte)(double)obj;
                                break;
                            case TypeCode.Decimal:
                                newObj = (sbyte)(decimal)obj;
                                break;
                        }
                        break;
                    case TypeCode.Int16:
                        switch (fromTypeCode)
                        {
                            case TypeCode.Int16:
                                newObj = obj;
                                break;
                            case TypeCode.UInt16:
                                newObj = (short)(ushort)obj;
                                break;
                            case TypeCode.Int32:
                                newObj = (short)(int)obj;
                                break;
                            case TypeCode.UInt32:
                                newObj = (short)(uint)obj;
                                break;
                            case TypeCode.Int64:
                                newObj = (short)(long)obj;
                                break;
                            case TypeCode.UInt64:
                                newObj = (short)(ulong)obj;
                                break;
                            case TypeCode.Single:
                                newObj = (short)(float)obj;
                                break;
                            case TypeCode.Double:
                                newObj = (short)(double)obj;
                                break;
                            case TypeCode.Decimal:
                                newObj = (short)(decimal)obj;
                                break;
                        }
                        break;
                    case TypeCode.UInt16:
                        switch (fromTypeCode)
                        {
                            case TypeCode.SByte:
                                newObj = (ushort)(sbyte)obj;
                                break;
                            case TypeCode.Int16:
                                newObj = (ushort)(short)obj;
                                break;
                            case TypeCode.UInt16:
                                newObj = obj;
                                break;
                            case TypeCode.Int32:
                                newObj = (ushort)(int)obj;
                                break;
                            case TypeCode.UInt32:
                                newObj = (ushort)(uint)obj;
                                break;
                            case TypeCode.Int64:
                                newObj = (ushort)(long)obj;
                                break;
                            case TypeCode.UInt64:
                                newObj = (ushort)(ulong)obj;
                                break;
                            case TypeCode.Single:
                                newObj = (ushort)(float)obj;
                                break;
                            case TypeCode.Double:
                                newObj = (ushort)(double)obj;
                                break;
                            case TypeCode.Decimal:
                                newObj = (ushort)(decimal)obj;
                                break;
                        }
                        break;
                    case TypeCode.Int32:
                        switch (fromTypeCode)
                        {
                            case TypeCode.Int32:
                                newObj = obj;
                                break;
                            case TypeCode.UInt32:
                                newObj = (int)(uint)obj;
                                break;
                            case TypeCode.Int64:
                                newObj = (int)(long)obj;
                                break;
                            case TypeCode.UInt64:
                                newObj = (int)(ulong)obj;
                                break;
                            case TypeCode.Single:
                                newObj = (int)(float)obj;
                                break;
                            case TypeCode.Double:
                                newObj = (int)(double)obj;
                                break;
                            case TypeCode.Decimal:
                                newObj = (int)(decimal)obj;
                                break;
                        }
                        break;
                    case TypeCode.UInt32:
                        switch (fromTypeCode)
                        {
                            case TypeCode.SByte:
                                newObj = (uint)(sbyte)obj;
                                break;
                            case TypeCode.Int16:
                                newObj = (uint)(short)obj;
                                break;
                            case TypeCode.Int32:
                                newObj = (uint)(int)obj;
                                break;
                            case TypeCode.UInt32:
                                newObj = obj;
                                break;
                            case TypeCode.Int64:
                                newObj = (uint)(long)obj;
                                break;
                            case TypeCode.UInt64:
                                newObj = (uint)(ulong)obj;
                                break;
                            case TypeCode.Single:
                                newObj = (uint)(float)obj;
                                break;
                            case TypeCode.Double:
                                newObj = (uint)(double)obj;
                                break;
                            case TypeCode.Decimal:
                                newObj = (uint)(decimal)obj;
                                break;
                        }
                        break;
                    case TypeCode.Int64:
                        switch (fromTypeCode)
                        {
                            case TypeCode.Int64:
                                newObj = obj;
                                break;
                            case TypeCode.UInt64:
                                newObj = (long)(ulong)obj;
                                break;
                            case TypeCode.Single:
                                newObj = (long)(float)obj;
                                break;
                            case TypeCode.Double:
                                newObj = (long)(double)obj;
                                break;
                            case TypeCode.Decimal:
                                newObj = (long)(decimal)obj;
                                break;
                        }
                        break;
                    case TypeCode.UInt64:
                        switch (fromTypeCode)
                        {
                            case TypeCode.SByte:
                                newObj = (ulong)(sbyte)obj;
                                break;
                            case TypeCode.Int16:
                                newObj = (ulong)(short)obj;
                                break;
                            case TypeCode.Int32:
                                newObj = (ulong)(int)obj;
                                break;
                            case TypeCode.Int64:
                                newObj = (ulong)(long)obj;
                                break;
                            case TypeCode.UInt64:
                                newObj = obj;
                                break;
                            case TypeCode.Single:
                                newObj = (ulong)(float)obj;
                                break;
                            case TypeCode.Double:
                                newObj = (ulong)(double)obj;
                                break;
                            case TypeCode.Decimal:
                                newObj = (ulong)(decimal)obj;
                                break;
                        }
                        break;
                    case TypeCode.Single:
                        switch (fromTypeCode)
                        {
                            case TypeCode.Char:
                                newObj = (float)(char)obj;
                                break;
                            case TypeCode.Single:
                                newObj = obj;
                                break;
                            case TypeCode.Double:
                                newObj = (float)(double)obj;
                                break;
                        }
                        break;
                    case TypeCode.Double:
                        switch (fromTypeCode)
                        {
                            case TypeCode.Char:
                                newObj = (double)(char)obj;
                                break;
                            case TypeCode.Double:
                                newObj = obj;
                                break;
                        }
                        break;
                    case TypeCode.Decimal:
                        switch (fromTypeCode)
                        {
                            case TypeCode.Single:
                                newObj = (decimal)(float)obj;
                                break;
                            case TypeCode.Double:
                                newObj = (decimal)(double)obj;
                                break;
                            case TypeCode.Decimal:
                                newObj = obj;
                                break;
                        }
                        break;
                }
                if (newObj == null)
                {
                    //Type fromType = obj.GetType();
                    if (toType == typeof(IntPtr))
                    {
                        if (fromTypeCode == TypeCode.Int32)
                            newObj = (IntPtr)(int)obj;
                        else if (fromTypeCode == TypeCode.Int64)
                            newObj = (IntPtr)(long)obj;
                        //else if (fromType == typeof(void*))
                        //    newObj = (IntPtr)(void*)obj;
                    }
                    else if (toType == typeof(UIntPtr))
                    {
                        if (fromTypeCode == TypeCode.UInt32)
                            newObj = (UIntPtr)(uint)obj;
                        else if (fromTypeCode == TypeCode.UInt64)
                            newObj = (UIntPtr)(ulong)obj;
                        //else if (fromType == typeof(void*))
                        //    newObj = (UIntPtr)(void*)obj;
                    }
                    else if (IsNullableType(toType))
                    {
                        // If the object type differs from the nullable's type element type, convert it
                        Type elementType = toType.GetGenericArguments()[0];
                        if (fromTypeCode != Type.GetTypeCode(elementType))
                            obj = ChangeType(obj, elementType);
                        // It's unfortunately not possible to return a nullable type as an object, because
                        // nullable types can't be boxed - they are implicitly converted to either null or their
                        // wrapped type.  This means that a cast to an 'int?' will evaluate as an 'int' type.
                        // Fixing this for Nova's purposes would require a custom Nullable type.
                        //newObj = Activator.CreateInstance(toType, obj);
                        newObj = obj;
                    }
                    else if (toType.IsPointer)
                        newObj = obj;
                    else
                        newObj = Convert.ChangeType(obj, toType);
                }
            }
            catch { }
            return newObj;
        }

        #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)


Written By
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).

Comments and Discussions