File: Hosting\ImageSources\ImageSourceServiceProvider.cs
Web Access
Project: src\src\Core\src\Core.csproj (Microsoft.Maui)
#nullable enable
 
using System;
using System.Collections.Concurrent;
using System.Diagnostics.CodeAnalysis;
using Microsoft.Maui.Hosting.Internal;
 
namespace Microsoft.Maui.Hosting
{
	sealed class ImageSourceServiceProvider : MauiFactory, IImageSourceServiceProvider
	{
		static readonly string ImageSourceInterface = typeof(IImageSource).FullName!;
		static readonly Type ImageSourceServiceType = typeof(IImageSourceService<>);
 
		readonly ConcurrentDictionary<Type, Type> _imageSourceCache = new ConcurrentDictionary<Type, Type>();
		readonly ConcurrentDictionary<Type, Type> _serviceCache = new ConcurrentDictionary<Type, Type>();
 
		readonly ImageSourceToImageSourceServiceTypeMapping _imageSourceMapping;
 
		public ImageSourceServiceProvider(IImageSourceServiceCollection collection, IServiceProvider hostServiceProvider)
			: base(collection)
		{
			_imageSourceMapping = ImageSourceToImageSourceServiceTypeMapping.GetInstance(collection);
			HostServiceProvider = hostServiceProvider;
		}
 
		public IServiceProvider HostServiceProvider { get; }
 
		public IImageSourceService? GetImageSourceService(Type imageSource)
		{
			var imageSourceService = _serviceCache.GetOrAdd(imageSource, _imageSourceMapping.FindImageSourceServiceType);
			return (IImageSourceService?)GetService(imageSourceService);
		}
 
#if !NETSTANDARD
		[RequiresDynamicCode("The GetImageSourceServiceType method is not AOT compatible. Use GetImageSourceService instead.")]
#endif
		[RequiresUnreferencedCode("The GetImageSourceServiceType method is not trimming compatible. Use GetImageSourceService instead.")]
		public Type GetImageSourceServiceType(Type imageSource)
		{
			return _serviceCache.GetOrAdd(imageSource, CreateImageSourceServiceTypeCacheEntry);
 
			Type CreateImageSourceServiceTypeCacheEntry(Type type)
			{
				var genericConcreteType = ImageSourceServiceType.MakeGenericType(type);
 
				if (genericConcreteType != null && InternalCollection.TryGetService(genericConcreteType, out _))
				{
					return genericConcreteType;
				}
 
				return ImageSourceServiceType.MakeGenericType(GetImageSourceType(type));
			}
		}
 
		[RequiresUnreferencedCode("The GetImageSourceType method is not trimming compatible. Use GetImageSourceService instead.")]
		public Type GetImageSourceType(Type imageSource)
		{
			return _imageSourceCache.GetOrAdd(imageSource, CreateImageSourceTypeCacheEntry);
 
			Type CreateImageSourceTypeCacheEntry(Type type)
			{
				if (type.IsInterface)
				{
					if (type.GetInterface(ImageSourceInterface) != null)
					{
						return type;
					}
				}
				else
				{
					foreach (var directInterface in type.GetInterfaces())
					{
						if (directInterface.GetInterface(ImageSourceInterface) != null)
						{
							return directInterface;
						}
					}
				}
 
				throw new InvalidOperationException($"Unable to find the image source type because none of the interfaces on {type.Name} were derived from {nameof(IImageSource)}.");
			}
		}
	}
}