| File: System\ComponentModel\Container.cs | Web Access |
| Project: src\runtime\src\libraries\System.ComponentModel.TypeConverter\src\System.ComponentModel.TypeConverter.csproj (System.ComponentModel.TypeConverter) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics.CodeAnalysis; namespace System.ComponentModel { /// <summary> /// Encapsulates zero or more components. /// </summary> public class Container : IContainer { private ISite?[]? _sites; private int _siteCount; private ComponentCollection? _components; private ContainerFilterService? _filter; private bool _checkedFilter; private readonly object _syncObj = new object(); ~Container() => Dispose(false); /// <summary> /// Adds the specified component to the <see cref='System.ComponentModel.Container'/> /// The component is unnamed. /// </summary> [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "No name is provided.")] public virtual void Add(IComponent? component) => Add(component, null); // Adds a component to the container. /// <summary> /// Adds the specified component to the <see cref='System.ComponentModel.Container'/> and assigns /// a name to it. /// </summary> [RequiresUnreferencedCode("The Type of components in the container cannot be statically discovered to validate the name.")] public virtual void Add(IComponent? component, string? name) { lock (_syncObj) { if (component == null) { return; } ISite? site = component.Site; if (site != null && site.Container == this) { return; } if (_sites == null) { _sites = new ISite[4]; } else { // Validate that new components have either a null name or a unique one. ValidateName(component, name); if (_sites.Length == _siteCount) { ISite[] newSites = new ISite[_siteCount * 2]; Array.Copy(_sites, newSites, _siteCount); _sites = newSites; } } site?.Container!.Remove(component); ISite newSite = CreateSite(component, name); _sites[_siteCount++] = newSite; component.Site = newSite; _components = null; } } /// <summary> /// Creates a Site <see cref='System.ComponentModel.ISite'/> for the given <see cref='System.ComponentModel.IComponent'/> /// and assigns the given name to the site. /// </summary> protected virtual ISite CreateSite(IComponent component, string? name) { return new Site(component, this, name); } /// <summary> /// Disposes of the container. A call to the Dispose method indicates that /// the user of the container has no further need for it. /// /// The implementation of Dispose must: /// /// (1) Remove any references the container is holding to other components. /// This is typically accomplished by assigning null to any fields that /// contain references to other components. /// /// (2) Release any system resources that are associated with the container, /// such as file handles, window handles, or database connections. /// /// (3) Dispose of child components by calling the Dispose method of each. /// /// Ideally, a call to Dispose will revert a container to the state it was /// in immediately after it was created. However, this is not a requirement. /// Following a call to its Dispose method, a container is permitted to raise /// exceptions for operations that cannot meaningfully be performed. /// </summary> public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (disposing) { lock (_syncObj) { while (_siteCount > 0) { ISite site = _sites![--_siteCount]!; site.Component.Site = null; site.Component.Dispose(); } _sites = null; _components = null; } } } protected virtual object? GetService(Type service) => service == typeof(IContainer) ? this : null; /// <summary> /// Gets all the components in the <see cref='System.ComponentModel.Container'/>. /// </summary> public virtual ComponentCollection Components { get { lock (_syncObj) { if (_components == null) { IComponent[] result = new IComponent[_siteCount]; for (int i = 0; i < _siteCount; i++) { result[i] = _sites![i]!.Component; } _components = new ComponentCollection(result); // At each component add, if we don't yet have a filter, look for one. // Components may add filters. if (_filter == null && _checkedFilter) { _checkedFilter = false; } } if (!_checkedFilter) { _filter = GetService(typeof(ContainerFilterService)) as ContainerFilterService; _checkedFilter = true; } if (_filter != null) { ComponentCollection filteredComponents = _filter.FilterComponents(_components); if (filteredComponents != null) { _components = filteredComponents; } } return _components; } } } /// <summary> /// Removes a component from the <see cref='System.ComponentModel.Container'/>. /// </summary> public virtual void Remove(IComponent? component) => Remove(component, false); private void Remove(IComponent? component, bool preserveSite) { lock (_syncObj) { ISite? site = component?.Site; if (site == null || site.Container != this) { return; } if (!preserveSite) { component!.Site = null; } for (int i = 0; i < _siteCount; i++) { if (_sites![i] == site) { _siteCount--; Array.Copy(_sites, i + 1, _sites, i, _siteCount - i); _sites[_siteCount] = null; _components = null; break; } } } } protected void RemoveWithoutUnsiting(IComponent? component) => Remove(component, true); /// <summary> /// Validates that the given name is valid for a component. The default implementation /// verifies that name is either null or unique compared to the names of other /// components in the container. /// </summary> [RequiresUnreferencedCode("The Type of components in the container cannot be statically discovered.")] protected virtual void ValidateName(IComponent component, string? name) { ArgumentNullException.ThrowIfNull(component); if (name != null) { lock (_syncObj) { for (int i = 0; i < Math.Min(_siteCount, _sites!.Length); i++) { ISite? s = _sites[i]; if (s?.Name != null && string.Equals(s.Name, name, StringComparison.OrdinalIgnoreCase) && s.Component != component) { InheritanceAttribute inheritanceAttribute = (InheritanceAttribute)TypeDescriptor.GetAttributes(s.Component)[typeof(InheritanceAttribute)]!; if (inheritanceAttribute.InheritanceLevel != InheritanceLevel.InheritedReadOnly) { throw new ArgumentException(SR.Format(SR.DuplicateComponentName, name)); } } } } } } private sealed class Site : ISite { private string? _name; internal Site(IComponent component, Container container, string? name) { Component = component; Container = container; _name = name; } /// <summary> /// The component sited by this component site. /// </summary> public IComponent Component { get; } /// <summary> /// The container in which the component is sited. /// </summary> public IContainer Container { get; } public object? GetService(Type service) { return ((service == typeof(ISite)) ? this : ((Container)Container).GetService(service)); } /// <summary> /// Indicates whether the component is in design mode. /// </summary> public bool DesignMode => false; /// <summary> /// The name of the component. /// </summary> public string? Name { get => _name; [RequiresUnreferencedCode("The Type of components in the container cannot be statically discovered to validate the name.")] set { if (value == null || _name == null || !value.Equals(_name)) { ((Container)Container).ValidateName(Component, value); _name = value; } } } } } }