Created
December 23, 2024 21:07
-
-
Save gusarov/cf4aed5cff52b4404e28d173b18083ac to your computer and use it in GitHub Desktop.
Prevent duplicated service registration before build using decorator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Microsoft.Extensions.DependencyInjection; | |
using Microsoft.Extensions.Hosting; | |
using System.Collections; | |
using System.Diagnostics.CodeAnalysis; | |
namespace CompanyName; | |
internal class Program | |
{ | |
private static void Main(string[] args) | |
{ | |
var appBuidler = Host.CreateApplicationBuilder(); | |
var serviceCollection = new ConstrainedServiceCollection(appBuidler.Services); | |
serviceCollection.AddSingleton<IService, Serivce1>(); | |
serviceCollection.AddSingleton<IService, Serivce2>(); | |
var app = appBuidler.Build(); | |
app.Run(); | |
} | |
} | |
interface IService | |
{ | |
} | |
class Serivce1 : IService | |
{ | |
} | |
class Serivce2 : IService | |
{ | |
} | |
class ConstrainedServiceCollection : IServiceCollection | |
{ | |
private readonly List<ServiceDescriptor> _descriptors = new List<ServiceDescriptor>(); | |
private readonly IServiceCollection _underlyingServices; | |
private readonly Dictionary<Type, ServiceDescriptor> _byType = new Dictionary<Type, ServiceDescriptor>(); | |
private bool _isReadOnly; | |
public ConstrainedServiceCollection(IServiceCollection underlyingServices) | |
{ | |
_underlyingServices = underlyingServices; | |
} | |
public int Count => _descriptors.Count; | |
public bool IsReadOnly => _isReadOnly; | |
public void MakeReadOnly() | |
{ | |
_isReadOnly = true; | |
} | |
public ServiceDescriptor this[int index] | |
{ | |
get | |
{ | |
return _descriptors[index]; | |
} | |
set | |
{ | |
CheckReadOnly(); | |
_descriptors[index] = value; | |
} | |
} | |
private void CheckReadOnly() | |
{ | |
if (_isReadOnly) | |
{ | |
throw new Exception(); | |
} | |
} | |
void CheckExisting(ServiceDescriptor item) | |
{ | |
if (!_byType.TryAdd(item.ServiceType, item)) | |
{ | |
var existing = _byType[item.ServiceType]; | |
throw new Exception($"Can not add Service {item.ServiceType.Name} implemented as {item.ImplementationType?.Name} because it is already registered as {existing.ImplementationType?.Name}"); | |
} | |
} | |
public void Clear() | |
{ | |
CheckReadOnly(); | |
_descriptors.Clear(); | |
} | |
public bool Contains(ServiceDescriptor item) | |
{ | |
return _descriptors.Contains(item); | |
} | |
public void CopyTo(ServiceDescriptor[] array, int arrayIndex) | |
{ | |
_descriptors.CopyTo(array, arrayIndex); | |
} | |
public bool Remove(ServiceDescriptor item) | |
{ | |
CheckReadOnly(); | |
return _descriptors.Remove(item); | |
} | |
public IEnumerator<ServiceDescriptor> GetEnumerator() | |
{ | |
return _descriptors.GetEnumerator(); | |
} | |
void ICollection<ServiceDescriptor>.Add(ServiceDescriptor item) | |
{ | |
CheckReadOnly(); | |
CheckExisting(item); | |
_descriptors.Add(item); | |
} | |
IEnumerator IEnumerable.GetEnumerator() | |
{ | |
return GetEnumerator(); | |
} | |
public int IndexOf(ServiceDescriptor item) | |
{ | |
return _descriptors.IndexOf(item); | |
} | |
public void Insert(int index, ServiceDescriptor item) | |
{ | |
CheckReadOnly(); | |
CheckExisting(item); | |
_descriptors.Insert(index, item); | |
} | |
public void RemoveAt(int index) | |
{ | |
CheckReadOnly(); | |
_descriptors.RemoveAt(index); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment