Description
ServiceKeys, ServiceTypes, ServiceLifetimes, and ServiceKeys<T> in ServiceProviderFactory.cs are declared as public classes that inherit from HashSet<>. This exposes mutable collection APIs (.Add(), .Remove(), .Clear()) to all consumers of the library.
public class ServiceKeys<T> : HashSet<object> { ... }
public class ServiceKeys : HashSet<object>;
public class ServiceTypes : HashSet<Type>;
public class ServiceLifetimes { ... } // has public Add() method
Impact
Library consumers can mutate these tracking collections after the service provider is built, potentially corrupting the IsServiceRegistered / IsKeyedServiceRegistered / lifetime-check infrastructure.
Suggested Fix
These types are only used internally by ServiceProviderExtensions. Consider:
- Making them
internal (they're registered as singletons and resolved by type, so internal visibility is sufficient)
- Or wrapping them in read-only interfaces for the public API
Note: ServiceKeys<T> needs to remain resolvable by the generic GetAllServices method, but that can work with internal visibility since both are in the same assembly.
Description
ServiceKeys,ServiceTypes,ServiceLifetimes, andServiceKeys<T>inServiceProviderFactory.csare declared aspublicclasses that inherit fromHashSet<>. This exposes mutable collection APIs (.Add(),.Remove(),.Clear()) to all consumers of the library.Impact
Library consumers can mutate these tracking collections after the service provider is built, potentially corrupting the
IsServiceRegistered/IsKeyedServiceRegistered/ lifetime-check infrastructure.Suggested Fix
These types are only used internally by
ServiceProviderExtensions. Consider:internal(they're registered as singletons and resolved by type, so internal visibility is sufficient)Note:
ServiceKeys<T>needs to remain resolvable by the genericGetAllServicesmethod, but that can work withinternalvisibility since both are in the same assembly.