/// <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); }