| File: Hosting\ImageSources\ImageSourceToImageSourceServiceTypeMapping.cs | Web Access |
| Project: src\src\Core\src\Core.csproj (Microsoft.Maui) |
using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; namespace Microsoft.Maui.Hosting { internal sealed class ImageSourceToImageSourceServiceTypeMapping { private static readonly ConcurrentDictionary<IImageSourceServiceCollection, ImageSourceToImageSourceServiceTypeMapping> s_instances = new(); internal static ImageSourceToImageSourceServiceTypeMapping GetInstance(IImageSourceServiceCollection collection) => s_instances.GetOrAdd(collection, static _ => new ImageSourceToImageSourceServiceTypeMapping()); private readonly Dictionary<Type, Type> _concreteTypeMapping = new(); private readonly Dictionary<Type, Type> _interfaceTypeMapping = new(); public void Add<TImageSource, TImageSourceService>() where TImageSource : IImageSource where TImageSourceService : class, IImageSourceService<TImageSource> { if (typeof(TImageSource).IsInterface) { _interfaceTypeMapping[typeof(TImageSource)] = typeof(TImageSourceService); } else { _concreteTypeMapping[typeof(TImageSource)] = typeof(TImageSourceService); } } public Type FindImageSourceServiceType(Type type) { Debug.Assert(typeof(IImageSource).IsAssignableFrom(type)); if (_concreteTypeMapping.TryGetValue(type, out var exactImageSourceService) || _interfaceTypeMapping.TryGetValue(type, out exactImageSourceService)) { return exactImageSourceService; } return FindImageSourceServiceMapping(type, _concreteTypeMapping) ?? FindImageSourceServiceMapping(type, _interfaceTypeMapping) ?? throw new InvalidOperationException($"Unable to find a {nameof(IImageSourceService)} corresponding to {type}. Please register a service for {type} using `ImageSourceServiceCollectionExtensions.AddService`"); } private static Type? FindImageSourceServiceMapping(Type type, Dictionary<Type, Type> mapping) { Type? bestImageSource = null; Type? bestImageSourceService = null; foreach (var (imageSource, imageSourceService) in mapping) { if (imageSource.IsAssignableFrom(type)) { if (bestImageSource is null || bestImageSource.IsAssignableFrom(imageSource)) { bestImageSource = imageSource; bestImageSourceService = imageSourceService; } else if (!imageSource.IsAssignableFrom(bestImageSource)) { // This exception can be thrown when the image source implements two interfaces that aren't derived from each other // which both have a registered image source service to them. // For example, consider this setup: // class MyImageSource : IStreamImageSource, IUriImageSource { ... } // // services.AddService<IStreamImageSource, StreamImageSourceService>(); // services.AddService<IUriImageSource, UriImageSourceService>(); // // var imageSourceService = provider.GetImageSourceService(typeof(MyImageSource)); // ambiguous match: both StreamImageSourceService and UriImageSourceService are registered for MyImageSource throw new InvalidOperationException($"Unable to find a single {nameof(IImageSourceService)} corresponding to {type}. There is an ambiguous match between {bestImageSourceService} ({bestImageSource}) and {imageSourceService} ({imageSource})."); } } } return bestImageSourceService; } } #if NETSTANDARD internal static class KeyValuePairExtensions { internal static void Deconstruct(this KeyValuePair<Type, Type> pair, out Type key, out Type value) { key = pair.Key; value = pair.Value; } } #endif }