public void CreateTypeIsOnlyInvokedOnceOnSuccess()
        {
            int invocationCount = 0;

            Func <Type, Type> createTypeDelegate =
                type =>
            {
                invocationCount++;
                return(typeof(MyProxyClass));
            };

            var cache = new ProxyTypeCache();


            for (int i = 0; i < 2; i++)
            {
                Assert.AreEqual(typeof(MyProxyClass), cache.GetProxyType(typeof(IMyInterface), createTypeDelegate));
            }

            Assert.AreEqual(1, invocationCount);
        }
        public void CreateTypeIsOnlyInvokedOnceOnFailure()
        {
            int invocationCount     = 0;
            var createTypeException = new Exception();

            Func <Type, Type> createTypeDelegate =
                type =>
            {
                invocationCount++;
                throw createTypeException;
            };

            var cache = new ProxyTypeCache();

            for (var i = 0; i < 2; i++)
            {
                var ex = Assert.Throws <InvalidOperationException>(() => cache.GetProxyType(typeof(IMyInterface), createTypeDelegate));
                Assert.AreSame(createTypeException, ex.InnerException);
            }

            Assert.AreEqual(1, invocationCount);
        }
            public ProxyBuilderContext(ProxyTypeCache cache, Type targetType, Type sourceType)
            {
                Cache = cache;

                Key = new Tuple<Type, Type>(sourceType, targetType);
                Visited = new Dictionary<Tuple<Type, Type>, VerificationResult>();
            }
        public static Type GetProxyType(ProxyTypeCache cache, Type targetType, Type sourceType)
        {
            if (targetType.IsAssignableFrom(sourceType))
            {
                return null;
            }

            var key = new Tuple<Type, Type>(sourceType, targetType);

            ProxyTypeCacheResult result;
            if (!cache.TryGetValue(key, out result))
            {
                var context = new ProxyBuilderContext(cache, targetType, sourceType);

                // Check that all required types are proxy-able - this will create the TypeBuilder, Constructor,
                // and property mappings.
                //
                // We need to create the TypeBuilder and Constructor up front to deal with cycles that can occur
                // when generating the proxy properties.
                if (!VerifyProxySupport(context, context.Key))
                {
                    var error = cache[key];
                    Debug.Assert(error != null && error.IsError);
                    throw new InvalidOperationException(error.Error);
                }

                Debug.Assert(context.Visited.ContainsKey(context.Key));

                // Now that we've generated all of the constructors for the proxies, we can generate the properties.
                foreach (var verificationResult in context.Visited)
                {
                    if (verificationResult.Value.Mappings != null)
                    {
                        AddProperties(
                            context,
                            verificationResult.Value.TypeBuilder,
                            verificationResult.Value.Mappings);
                    }
                }

                // Now generate the type
                foreach (var verificationResult in context.Visited)
                {
                    if (verificationResult.Value.TypeBuilder != null)
                    {
                        verificationResult.Value.Type = verificationResult.Value.TypeBuilder.CreateTypeInfo().AsType();
                    }
                }

                // We only want to publish the results after all of the proxies are totally generated.
                foreach (var verificationResult in context.Visited)
                {
                    cache[verificationResult.Key] = ProxyTypeCacheResult.FromType(
                        verificationResult.Key,
                        verificationResult.Value.Type,
                        verificationResult.Value.Constructor);
                }

                return context.Visited[context.Key].Type;
            }
            else if (result.IsError)
            {
                throw new InvalidOperationException(result.Error);
            }
            else if (result.Type == null)
            {
                // This is an identity convertion
                return null;
            }
            else
            {
                return result.Type;
            }
        }
 public void SetUp()
 {
     _builder = new ProxyBuilder("ProxyTypeCacheTests", "ProxyTypeCacheTests.dll");
     _cache = new ProxyTypeCache(_builder);
 }