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
}