/// <summary> /// Gets the DuckProxyType<TInterface> object for a given duck type. /// </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="duckType">Type of object being casted.</param> /// <returns>The duck proxy type to use to cast or prepare for casting.</returns> private static DuckProxyType <TInterface> GetProxyType(Type duckType) { DuckProxyType <TInterface> proxyType = 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); // 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 (s_ProxyTypes.ContainsKey(type)) { proxyType = s_ProxyTypes[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(type)) { proxyType = new DuckProxyType <TInterface>(type); 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 DuckProxyType <TInterface>(duckType); } else { // If we got to this point, the cast is valid and it is ok to add the proxy type to the dictionary. s_ProxyTypes.Add(proxyType.m_DuckType, proxyType); } } return(proxyType); }
/// <summary> /// Calls the static WrapDuck method of the generated proxy type to initialize a new instance of /// the proxy type with a given duck object. /// </summary> /// <param name="duck">Duck object that the new proxy object should forward calls to.</param> /// <returns> /// An instance of the proxy type, which implements TInterface, initialized with the given duck /// object. /// </returns> internal static TInterface WrapDuck(object duck) { DuckProxyType <TInterface> proxyType = GetProxyType(duck.GetType()); // Make sure the proxy type is generated before we try to call it. proxyType.GenerateProxyType(); // Call wrap method in the proxy type to create an instance of the proxy for the duck and return it. return(proxyType.m_WrapDuck(duck)); }