/// <summary> /// Creates and returns an instance of a class or interface T with given constructor arguments (<paramref name="data"/>). /// </summary> /// <typeparam name="T">type of the interface to instantiate</typeparam> /// <param name="instantiatorKey"></param> /// <param name="data"></param> /// <returns></returns> /// <exception cref="InstantiatorException"></exception> public T Instantiate(InstantiatorKey instantiatorKey, params object[] data) { try { var instance = CreateInstance(instantiatorKey, data); if (instance != null) { return(instance); } // OK. We did not find an instantiator. Let's try to create one. First of all let's lock an object var lockObject1 = new object(); lock (lockObject1) { if (InstantiatorLocks.TryAdd(instantiatorKey, lockObject1)) { // if we ended up here, it means that we were first Instantiators.AddRange(CreateInstantiatorsForPackage(instantiatorKey)); } else { // some other process have already created (or creating) instantiator // Theoretically, it is quite possible to have previous process fail, so we will need to be careful about assuming that if we got here, // then we should have instantiators. lock (InstantiatorLocks[instantiatorKey]) { // try read from the instantiators first. Maybe it has already been successfully created instance = CreateInstance(instantiatorKey, data); if (instance != null) { return(instance); } Instantiators.AddRange(CreateInstantiatorsForPackage(instantiatorKey)); } } instance = CreateInstance(instantiatorKey, data); if (instance != null) { return(instance); } } } catch (Exception e) { throw new InstantiatorException("Error occurred during instantiation", e); } throw new InstantiatorException($"Unknown error. Instantiator failed to produce an instance of {instantiatorKey}", null); }
/// <summary> /// Creates an instance of a generic type T. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="instantiatorKey"></param> /// <param name="data"></param> /// <returns></returns> private static T CreateInstance(InstantiatorKey instantiatorKey, object[] data) { if (!Instantiators.ContainsKey(instantiatorKey)) { return(default(T)); } var instantiatorByType = Instantiators[instantiatorKey]; // here it make sense to concatenate params var paramsHash = data == null || !data.Any() ? "" : string.Join(", ", data.Select(d => d.GetType().FullName)); if (instantiatorByType.ContainsKey(paramsHash)) { return(instantiatorByType[paramsHash](data)); } throw new InstantiatorException( $"Constructor signature {paramsHash} not found for package {instantiatorKey}", null); }
/// <summary> /// Creates and returns an instance of a class or interface T with a single constructor argument (<paramref name="data"/>). /// </summary> /// <typeparam name="T">type of the interface to instantiate</typeparam> /// <param name="instantiatorKey"></param> /// <param name="data"></param> /// <returns></returns> /// <exception cref="InstantiatorException"></exception> public T Instantiate(InstantiatorKey instantiatorKey, object data) { return(Instantiate(instantiatorKey, new[] { data })); }
/// <summary> /// Creates and returns an instance of a class or interface T with no arguments. /// </summary> /// <typeparam name="T">type of the interface to instantiate</typeparam> /// <param name="instantiatorKey"></param> /// <returns></returns> /// <exception cref="InstantiatorException"></exception> public T Instantiate(InstantiatorKey instantiatorKey) { return(Instantiate(instantiatorKey, null)); }
/// <summary> /// Creates instantiators for all of the types in the package that can be instantiated /// </summary> /// <param name="instantiatorKey"></param> /// <returns></returns> /// <exception cref="InstantiatorCreationException"></exception> private Dictionary <InstantiatorKey, Dictionary <string, Instantiator <T> > > CreateInstantiatorsForPackage(InstantiatorKey instantiatorKey) { string packagePath; Directory.CreateDirectory(_rootPath); var returnDictionary = new Dictionary <InstantiatorKey, Dictionary <string, Instantiator <T> > >(); try { packagePath = _packageRetriever.Retrieve(_rootPath, instantiatorKey.PackageId, SemanticVersion.Parse(instantiatorKey.Version)); } catch (Exception e) { throw new InstantiatorCreationException( $"Package Retriever Failed to obtain the package {instantiatorKey.PackageId}.{instantiatorKey.Version}", e); } if (string.IsNullOrWhiteSpace(packagePath)) { throw new InstantiatorCreationException( $"Package Retriever Failed to obtain the package {instantiatorKey.PackageId}.{instantiatorKey.Version} from available sources", null); } // find the directory where the dlls are var libPath = Path.Combine(packagePath, "impromptu"); var hotAssemblies = PluginContext <T> .DiscoverHotAssemblies(libPath); if (hotAssemblies == null) { return(returnDictionary); } foreach (var hotType in hotAssemblies.SelectMany(impromptu => impromptu.ExportedTypes.Where( t => t.IsClass && typeof(T).IsAssignableFrom(t) && t.GetConstructors().Any()))) { returnDictionary.Add( new InstantiatorKey(instantiatorKey.PackageId, instantiatorKey.Version, hotType.FullName), hotType.GetConstructors().ToDictionary( ctor => !ctor.GetParameters().Any() ? "" : string.Join(", ", ctor.GetParameters().Select(p => p.ParameterType.FullName)), CreateInstantiator)); } return(returnDictionary); }