79614428

Date: 2025-05-09 15:23:36
Score: 0.5
Natty:
Report link

Improving on steven answer above https://stackoverflow.com/a/77559901/1875674

public class KeyServiceDictionary<TKey, TService> : IReadOnlyDictionary<TKey, TService>
{
    private readonly KeyedServiceCache _keyedServiceCache;
    private readonly IServiceProvider _serviceProvider;
    private readonly bool _isServiceEnumerable;
    private readonly Type _serviceType;
    private readonly IServiceProviderIsKeyedService _serviceProviderIsKeyedService;

    //caching
    private readonly Dictionary<TKey, TService> _resolvedServices = new Dictionary<TKey, TService>();

    public KeyServiceDictionary(KeyedServiceCache keyedServiceCache, IServiceProvider serviceProvider, IServiceProviderIsKeyedService serviceProviderIsKeyedService)
    {
        _isServiceEnumerable = typeof(TService).IsGenericType &&
                               typeof(TService).GetGenericTypeDefinition() == typeof(IEnumerable<>);

        _serviceType = _isServiceEnumerable? typeof(TService).GetGenericArguments()[0]: typeof(TService);

        _keyedServiceCache = keyedServiceCache;
        _serviceProvider = serviceProvider;

        _serviceProviderIsKeyedService = serviceProviderIsKeyedService;
    }

    public IEnumerator<KeyValuePair<TKey, TService>> GetEnumerator()
    {
        return new Enumerator(Keys.GetEnumerator(), this);
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    public int Count => Keys.Count();

    public bool ContainsKey(TKey key)
    {
        return Keys.Any(x => x.Equals(key));
    }

    public bool TryGetValue(TKey key, out TService value)
    {
        value = _serviceProvider.GetKeyedService<TService>(key);

        return value != null;
    }

    public TService this[TKey key]
    {
        get
        {
            if (!_serviceProviderIsKeyedService.IsKeyedService(_serviceType, key))
                throw new KeyNotFoundException($"Could not find Key:{key} in Dictionary");

            if (_resolvedServices.TryGetValue(key, out var service))
                return service;


            try
            {
                service = _isServiceEnumerable
                    ? (TService)_serviceProvider.GetKeyedServices(_serviceType, key)
                    : _serviceProvider.GetRequiredKeyedService<TService>(key);
            }
            catch (InvalidOperationException e)
            {
                throw new KeyNotFoundException($"Could not find Key:{key} in Dictionary", e);
            }
            
            _resolvedServices.Add(key, service);

            return service;
        }
    }

    public IEnumerable<TKey> Keys =>
        (_isServiceEnumerable
            ? _keyedServiceCache.GetKeys<TKey>(_serviceType)
            : _keyedServiceCache.GetKeys<TKey, TService>()).Where(k =>
            _serviceProviderIsKeyedService.IsKeyedService(_serviceType, _serviceType));

    public IEnumerable<TService> Values => Keys.Select(key => this[key]);

    private class Enumerator : IEnumerator<KeyValuePair<TKey, TService>>
    {
        private readonly IEnumerator<TKey> _keys;
        private readonly IReadOnlyDictionary<TKey, TService> _parentDictionary;
        private KeyValuePair<TKey, TService> _currentKeyPair;

        public Enumerator(IEnumerator<TKey> keys, IReadOnlyDictionary<TKey,TService> parentDictionary)
        {
            _keys = keys;
            _parentDictionary = parentDictionary;
        }

        public bool MoveNext()
        {
            return _keys.MoveNext();
        }

        public void Reset()
        {
            _keys.Reset();
        }

        private KeyValuePair<TKey, TService> GetCurrent()
        {
            var service = _parentDictionary[_keys.Current];
            _currentKeyPair = new KeyValuePair<TKey, TService>(_keys.Current, service);
            return _currentKeyPair;
        }

        public object Current => GetCurrent();

        KeyValuePair<TKey, TService> IEnumerator<KeyValuePair<TKey, TService>>.Current => GetCurrent();

        public void Dispose()
        {

        }
    }
}
public static class ServiceExtensions
{
    public static void WithKeyServiceDictionarySupport(this IServiceCollection serviceCollection)
    {
        serviceCollection.AddSingleton(s => new KeyedServiceCache(serviceCollection));
        serviceCollection.AddTransient(typeof(IReadOnlyDictionary<,>), typeof(KeyServiceDictionary<,>));
    }
}

Up to date Gist

Reasons:
  • Blacklisted phrase (1): stackoverflow
  • Long answer (-1):
  • Has code block (-0.5):
  • Low reputation (1):
Posted by: Tadhg Mulkern