/// <summary>
        /// Gets the InterfaceDuckProxyType object for a given cast.
        /// </summary>
        /// <param name="interfaceType">Type to cast to.</param>
        /// <param name="duckType">Static type being casted.</param>
        /// <returns>The duck proxy type to use to cast or prepare for casting.</returns>
        private InterfaceDuckProxyType GetProxyType(Type interfaceType, Type duckType)
        {
            InterfaceDuckProxyType proxyType = null;

            FromTypeTree <InterfaceDuckProxyType> fromTypeTree = null;

            if (s_ProxyTypeTree.ContainsKey(interfaceType))
            {
                fromTypeTree = s_ProxyTypeTree[interfaceType];

                if (fromTypeTree.ContainsKey(duckType))
                {
                    proxyType = fromTypeTree[duckType];
                }
            }

            if (proxyType == null)
            {
                proxyType = new InterfaceDuckProxyType(interfaceType, duckType, true);

                if (fromTypeTree == null)
                {
                    fromTypeTree = new FromTypeTree <InterfaceDuckProxyType>();
                    s_ProxyTypeTree.Add(interfaceType, fromTypeTree);
                }

                fromTypeTree.Add(proxyType.DuckType, proxyType);
            }

            return(proxyType);
        }
Example #2
0
        /// <summary>
        /// Gets the DelegateDuckProxyType object for a given duck type.
        /// </summary>
        /// <param name="toType">Type to be casted to.</param>
        /// <param name="fromType">Type of delegate to be casted.</param>
        /// <returns>The duck proxy type to use to cast or prepare for casting.</returns>
        private static DelegateDuckProxyType GetProxyType(Type toType, Type fromType)
        {
            DelegateDuckProxyType proxyType = null;

            FromTypeTree <DelegateDuckProxyType> fromTypeTree = null;

            if (s_ProxyTypeTree.ContainsKey(toType))
            {
                fromTypeTree = s_ProxyTypeTree[toType];

                if (fromTypeTree.ContainsKey(fromType))
                {
                    proxyType = fromTypeTree[fromType];
                }
            }

            if (proxyType == null)
            {
                proxyType = new DelegateDuckProxyType(toType, fromType);

                if (proxyType.CanProxy())
                {
                    if (fromTypeTree == null)
                    {
                        fromTypeTree = new FromTypeTree <DelegateDuckProxyType>();
                        s_ProxyTypeTree.Add(toType, fromTypeTree);
                    }

                    fromTypeTree.Add(fromType, proxyType);
                }
            }

            return(proxyType);
        }
        /// <summary>
        /// Determines whether a type can be casted to another type.
        /// </summary>
        /// <param name="toType">Type to cast to.</param>
        /// <param name="fromType">Type of object to be casted.</param>
        /// <returns>If an object of the given from type can be casted to the given to type, true; otherwise, false.</returns>
        public static bool CanCast(Type toType, Type fromType)
        {
            bool canCast;

            FromTypeTree <bool> canCastFromTree;

            if (s_CanCastTree.ContainsKey(toType))
            {
                canCastFromTree = s_CanCastTree[toType];
            }
            else
            {
                canCastFromTree = new FromTypeTree <bool>();
                s_CanCastTree.Add(toType, canCastFromTree);
            }

            if (canCastFromTree.ContainsKey(fromType))
            {
                canCast = canCastFromTree[fromType];
            }
            else
            {
                canCast = CanNormalCast(toType, fromType, true);
                if (!canCast)
                {
                    foreach (IDuckCaster caster in s_DuckCasters)
                    {
                        if (caster.CanCast(toType, fromType))
                        {
                            canCast = true;
                            break;
                        }
                    }
                }

                if (!canCast)
                {
                    foreach (IDuckCaster caster in s_DuckCasters)
                    {
                        if (caster.CouldUncast(toType, fromType))
                        {
                            canCast = true;
                            break;
                        }
                    }
                }

                canCastFromTree.Add(fromType, canCast);
            }

            return(canCast);
        }
        /// <summary>
        /// Determines whether a static type can be casted to another type.
        /// </summary>
        /// <param name="toType">Type to cast to.</param>
        /// <param name="staticType">Static type to be casted.</param>
        /// <returns>If the given static type can be casted to the given to type, true; otherwise, false.</returns>
        public static bool CanStaticCast(Type toType, Type staticType)
        {
            bool canCast;

            FromTypeTree <bool> canCastFromTree;

            if (s_CanStaticCastTree.ContainsKey(toType))
            {
                canCastFromTree = s_CanStaticCastTree[toType];
            }
            else
            {
                canCastFromTree = new FromTypeTree <bool>();
                s_CanStaticCastTree.Add(toType, canCastFromTree);
            }

            if (canCastFromTree.ContainsKey(staticType))
            {
                canCast = canCastFromTree[staticType];
            }
            else
            {
                canCast = false;
                foreach (IStaticDuckCaster caster in s_StaticDuckCasters)
                {
                    if (caster.CanStaticCast(toType, staticType))
                    {
                        canCast = true;
                        break;
                    }
                }

                canCastFromTree.Add(staticType, canCast);
            }

            return(canCast);
        }
        /// <summary>
        /// Gets the InterfaceDuckProxyType object for a given cast.
        /// </summary>
        /// <remarks>
        /// First, the most general type in the inheritance chain of the given type that implements all the
        /// members of TInterface is selected.  Then if a proxy type has already been generated, it returns
        /// it.  Finally, if not, it creates a new object and adds it to the dictionary.
        /// </remarks>
        /// <param name="interfaceType">Type to cast to.</param>
        /// <param name="duckType">Type of object being casted.</param>
        /// <returns>The duck proxy type to use to cast or prepare for casting.</returns>
        private InterfaceDuckProxyType GetProxyType(Type interfaceType, Type duckType)
        {
            InterfaceDuckProxyType proxyType = null;

            FromTypeTree <InterfaceDuckProxyType> fromTypeTree = null;

            // Examine the duck type's inheritance chain.
            List <Type> inheritanceChain = new List <Type>();
            Type        baseType         = duckType;

            do
            {
                inheritanceChain.Add(baseType);
                baseType = baseType.BaseType;
            }while (baseType != null);

            // Include interfaces in the inheritance chain.  We don't know which order, but it will still help.

            /*Type[] interfaces = duckType.GetInterfaces();
             * foreach (Type _interface in interfaces)
             * {
             *  inheritanceChain.Add(_interface);
             * }*/

            if (s_ProxyTypeTree.ContainsKey(interfaceType))
            {
                fromTypeTree = s_ProxyTypeTree[interfaceType];

                // Iterate the inheritance chain backwards (most general to most specialized) to find a proxy type
                // that has already been generated.
                for (int i = inheritanceChain.Count - 1; i >= 0; i--)
                {
                    Type type = inheritanceChain[i];

                    if (fromTypeTree.ContainsKey(type))
                    {
                        proxyType = fromTypeTree[type];
                        break;
                    }
                }
            }

            if (proxyType == null)
            {
                // Iterate the inheritance chain backwards (most general to most specialized) to find the most
                // general type that can be casted to TInterface.
                for (int i = inheritanceChain.Count - 1; i >= 0; i--)
                {
                    Type type = inheritanceChain[i];

                    if (CanCast(interfaceType, type))
                    {
                        proxyType = new InterfaceDuckProxyType(interfaceType, type, false);
                        break;
                    }
                }

                if (proxyType == null)
                {
                    // If proxyType is null, then DuckTyping.CanCast<>() returned false for every type in the
                    // inheritance chain.  The following line will cause an exception to be thrown when
                    // GenerateProxyType() is called.  The exception will indicate why the duck cannot be casted.
                    proxyType = new InterfaceDuckProxyType(interfaceType, duckType, false);
                }
                else
                {
                    // If we got to this point, the cast is valid and it is ok to add the proxy type to the tree.
                    if (fromTypeTree == null)
                    {
                        fromTypeTree = new FromTypeTree <InterfaceDuckProxyType>();
                        s_ProxyTypeTree.Add(interfaceType, fromTypeTree);
                    }

                    fromTypeTree.Add(proxyType.DuckType, proxyType);
                }
            }

            return(proxyType);
        }