/// <summary> /// Create an implementation of the given interface, using the given requester /// </summary> /// <typeparam name="T">Type of interface to implement</typeparam> /// <param name="requester">Requester to be used by the generated implementation</param> /// <returns>An implementation of the given interface</returns> public T CreateImplementation <T>(IRequester requester) { if (requester == null) { throw new ArgumentNullException(nameof(requester)); } // We have to be careful here. The common case is going to be fetching an existing creator. However in the case // that one doesn't yet exist, we can't try and create two of the same type at the same time. // We have a lock around creating all types, as that's simpler and probably won't be noticable in practice. if (TypeCreatorRegistry <T> .Creator == null) { lock (this.implementationBuilderLockObject) { // Two threads can fail the null test and acquire this lock in order. The first one will create the type. // Therefore the second one has to check for this... if (TypeCreatorRegistry <T> .Creator == null) { var implementationType = this.BuildImplementationImpl(typeof(T)); var creator = this.BuildCreator <T>(implementationType); TypeCreatorRegistry <T> .Creator = creator; } } } T implementation = TypeCreatorRegistry <T> .Creator(requester); return(implementation); }
/// <summary> /// Create an implementation of the given interface, using the given requester /// </summary> /// <typeparam name="T">Type of interface to implement</typeparam> /// <param name="requester">Requester to be used by the generated implementation</param> /// <returns>An implementation of the given interface</returns> public T CreateImplementation <T>(IRequester requester) { if (requester == null) { throw new ArgumentNullException(nameof(requester)); } // We have to be careful here. The common case is going to be fetching an existing creator. However in the case // that one doesn't yet exist, we can't try and create two of the same type at the same time. // We have a lock around creating all types, as that's simpler and probably won't be noticable in practice. if (TypeCreatorRegistry <T> .Creator == null) { lock (this.implementationFactoryLockObject) { // Two threads can fail the null test and acquire this lock in order. The first one will create the type. // Therefore the second one has to check for this... if (TypeCreatorRegistry <T> .Creator == null) { try { var implementationType = this.GetImplementation(typeof(T)); var creator = this.BuildCreator <T>(implementationType); TypeCreatorRegistry <T> .Creator = creator; } catch (Exception e) { // If they request the same type again, make sure they get the same exception. If we try and build the type // again, they'll get a different exception about a duplicate type. // Yes we nuke the stack trace, but that's not the end of the world since they don't care about our internals TypeCreatorRegistry <T> .Creator = x => throw e; throw; } } } } T implementation = TypeCreatorRegistry <T> .Creator(requester); return(implementation); }