/// <summary> /// Gets associate instance for specified parameters and result types. /// All associate created instances are cached and returned on the same calls further. /// </summary> /// <typeparam name="TKey1">First type to try to provide the associate for.</typeparam> /// <typeparam name="TKey2">Second type to try to provide the associate for.</typeparam> /// <typeparam name="TAssociate">Type of result to provide the associate for.</typeparam> /// <typeparam name="TResult">The type of result.</typeparam> /// <returns>Associate instance, if found; /// otherwise, <see langword="null"/>.</returns> /// <exception cref="InvalidOperationException"><c>InvalidOperationException</c>.</exception> protected TResult GetAssociate <TKey1, TKey2, TAssociate, TResult>() where TAssociate : class { var key = new TypePair(typeof(TKey1), typeof(TResult)); return((TResult)cache.GetValue(key, _key => { Type foundFor; TAssociate associate1 = CreateAssociate <TKey1, TAssociate>(out foundFor); TAssociate associate2 = CreateAssociate <TKey2, TAssociate>(out foundFor); // Preferring non-null ;) TAssociate associate; if (associate1 == null) { associate = associate2; } else if (associate2 == null) { associate = associate1; } else { // Both are non-null; preferring one of two associate = PreferAssociate <TKey1, TKey2, TAssociate>(associate1, associate2); } if (associate == null) { // Try to get complex associate (create it manually) associate = CreateCustomAssociate <TKey1, TKey2, TAssociate>(); if (associate == null) { var stringBuilder = new StringBuilder(); for (int i = 0; i < TypeSuffixes.Length; i++) { if (i != 0) { stringBuilder.Append(", "); } stringBuilder.Append(TypeSuffixes[i]); } throw new InvalidOperationException(string.Format( Strings.ExCantFindAssociate2, stringBuilder, typeof(TAssociate).GetShortName(), typeof(TKey1).GetShortName(), typeof(TKey2).GetShortName())); } } return ConvertAssociate <TKey1, TKey2, TAssociate, TResult>(associate); })); }
/// <inheritdoc/> protected override TAssociate CreateCustomAssociate <TKey1, TKey2, TAssociate>() { Pair <Type> keyTypePair = new Pair <Type>(typeof(TKey1), typeof(TKey2)); if (InProgress.ContainsKey(keyTypePair)) { throw new InvalidOperationException(Strings.ExRecursiveAssociateLookupDetected); } InProgress.Add(keyTypePair, true); try { TAssociate associate = base.CreateCustomAssociate <TKey1, TKey2, TAssociate>(); if (associate != null) { return(associate); } IAdvancedConverterFactory <TKey1> f1 = base.GetAssociate <TKey1, IAdvancedConverterFactory <TKey1>, IAdvancedConverterFactory <TKey1> >(); if (f1 != null) { associate = f1.CreateForwardConverter <TKey2>() as TAssociate; if (associate != null) { return(associate); } } IAdvancedConverterFactory <TKey2> f2 = base.GetAssociate <TKey2, IAdvancedConverterFactory <TKey2>, IAdvancedConverterFactory <TKey2> >(); if (f2 != null) { associate = f2.CreateBackwardConverter <TKey1>() as TAssociate; if (associate != null) { return(associate); } } return(null); } finally { InProgress.Remove(keyTypePair); } }