File: System\Data\Common\DataColumnMappingCollection.cs
Web Access
Project: src\src\libraries\System.Data.Common\src\System.Data.Common.csproj (System.Data.Common)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
 
namespace System.Data.Common
{
    public sealed class DataColumnMappingCollection : MarshalByRefObject, IColumnMappingCollection
    {
        private List<DataColumnMapping>? _items; // delay creation until AddWithoutEvents, Insert, CopyTo, GetEnumerator
 
        public DataColumnMappingCollection()
        {
        }
 
        // explicit ICollection implementation
        bool ICollection.IsSynchronized
        {
            get { return false; }
        }
        object ICollection.SyncRoot
        {
            get { return this; }
        }
 
        // explicit IList implementation
        bool IList.IsReadOnly
        {
            get { return false; }
        }
        bool IList.IsFixedSize
        {
            get { return false; }
        }
        object? IList.this[int index]
        {
            get
            {
                return this[index];
            }
            set
            {
                ValidateType(value);
                this[index] = (DataColumnMapping)value;
            }
        }
 
        // explicit IColumnMappingCollection implementation
        object IColumnMappingCollection.this[string index]
        {
            get
            {
                return this[index];
            }
            set
            {
                ValidateType(value);
                this[index] = (DataColumnMapping)value;
            }
        }
        IColumnMapping IColumnMappingCollection.Add(string? sourceColumnName, string? dataSetColumnName)
        {
            return Add(sourceColumnName, dataSetColumnName);
        }
        IColumnMapping IColumnMappingCollection.GetByDataSetColumn(string dataSetColumnName)
        {
            return GetByDataSetColumn(dataSetColumnName);
        }
 
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public int Count
        {
            get
            {
                return ((null != _items) ? _items.Count : 0);
            }
        }
 
        private static Type ItemType
        {
            get { return typeof(DataColumnMapping); }
        }
 
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public DataColumnMapping this[int index]
        {
            get
            {
                RangeCheck(index);
                return _items![index];
            }
            set
            {
                RangeCheck(index);
                Replace(index, value);
            }
        }
 
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public DataColumnMapping this[string sourceColumn]
        {
            get
            {
                int index = RangeCheck(sourceColumn);
                return _items![index];
            }
            set
            {
                int index = RangeCheck(sourceColumn);
                Replace(index, value);
            }
        }
 
        public int Add(object? value)
        {
            ValidateType(value);
            Add((DataColumnMapping)value);
            return Count - 1;
        }
 
        private DataColumnMapping Add(DataColumnMapping value)
        {
            AddWithoutEvents(value);
            return value;
        }
 
        public DataColumnMapping Add(string? sourceColumn, string? dataSetColumn)
        {
            return Add(new DataColumnMapping(sourceColumn, dataSetColumn));
        }
 
        public void AddRange(DataColumnMapping[] values)
        {
            AddEnumerableRange(values, false);
        }
 
        public void AddRange(System.Array values)
        {
            AddEnumerableRange(values, false);
        }
 
        /*/// <include file='doc\DataColumnMappingCollection.uex' path='docs/doc[@for="DataColumnMappingCollection.AddCloneOfRange"]/*' />
        public void AddCloneOfRange(IEnumerable values) {
            AddEnumerableRange(values, true);
        }*/
 
        private void AddEnumerableRange(Array values, bool doClone)
        {
            if (null == values)
            {
                throw ADP.ArgumentNull(nameof(values));
            }
            foreach (object value in values)
            {
                ValidateType(value);
            }
            if (doClone)
            {
                foreach (ICloneable value in values)
                {
                    AddWithoutEvents(value.Clone() as DataColumnMapping);
                }
            }
            else
            {
                foreach (DataColumnMapping value in values)
                {
                    AddWithoutEvents(value);
                }
            }
        }
 
        private void AddWithoutEvents([NotNull] DataColumnMapping? value)
        {
            Validate(-1, value);
            value.Parent = this;
            ArrayList().Add(value);
        }
 
        // implemented as a method, not as a property because the VS7 debugger
        // object browser calls properties to display their value, and we want this delayed
        private List<DataColumnMapping> ArrayList()
        {
            if (null == _items)
            {
                _items = new List<DataColumnMapping>();
            }
            return _items;
        }
 
        public void Clear()
        {
            if (0 < Count)
            {
                ClearWithoutEvents();
            }
        }
 
        private void ClearWithoutEvents()
        {
            if (null != _items)
            {
                foreach (DataColumnMapping item in _items)
                {
                    item.Parent = null;
                }
                _items.Clear();
            }
        }
 
        public bool Contains(string? value)
        {
            return (-1 != IndexOf(value));
        }
 
        public bool Contains(object? value)
        {
            return (-1 != IndexOf(value));
        }
 
        public void CopyTo(Array array, int index)
        {
            ((ICollection)ArrayList()).CopyTo(array, index);
        }
 
        public void CopyTo(DataColumnMapping[] array, int index)
        {
            ArrayList().CopyTo(array, index);
        }
 
        public DataColumnMapping GetByDataSetColumn(string value)
        {
            int index = IndexOfDataSetColumn(value);
            if (0 > index)
            {
                throw ADP.ColumnsDataSetColumn(value);
            }
            return _items![index];
        }
 
        public IEnumerator GetEnumerator()
        {
            return ArrayList().GetEnumerator();
        }
 
        public int IndexOf(object? value)
        {
            if (null != value)
            {
                ValidateType(value);
                for (int i = 0; i < Count; ++i)
                {
                    if (_items![i] == value)
                    {
                        return i;
                    }
                }
            }
            return -1;
        }
 
        public int IndexOf(string? sourceColumn)
        {
            if (!string.IsNullOrEmpty(sourceColumn))
            {
                int count = Count;
                for (int i = 0; i < count; ++i)
                {
                    if (0 == ADP.SrcCompare(sourceColumn, _items![i].SourceColumn))
                    {
                        return i;
                    }
                }
            }
            return -1;
        }
 
        public int IndexOfDataSetColumn(string? dataSetColumn)
        {
            if (!string.IsNullOrEmpty(dataSetColumn))
            {
                int count = Count;
                for (int i = 0; i < count; ++i)
                {
                    if (0 == ADP.DstCompare(dataSetColumn, _items![i].DataSetColumn))
                    {
                        return i;
                    }
                }
            }
            return -1;
        }
 
        public void Insert(int index, object? value)
        {
            ValidateType(value);
            Insert(index, (DataColumnMapping)value);
        }
 
        public void Insert(int index, DataColumnMapping value)
        {
            if (null == value)
            {
                throw ADP.ColumnsAddNullAttempt(nameof(value));
            }
            Validate(-1, value);
            value.Parent = this;
            ArrayList().Insert(index, value);
        }
 
        private void RangeCheck(int index)
        {
            if ((index < 0) || (Count <= index))
            {
                throw ADP.ColumnsIndexInt32(index, this);
            }
        }
 
        private int RangeCheck(string sourceColumn)
        {
            int index = IndexOf(sourceColumn);
            if (index < 0)
            {
                throw ADP.ColumnsIndexSource(sourceColumn);
            }
            return index;
        }
 
        public void RemoveAt(int index)
        {
            RangeCheck(index);
            RemoveIndex(index);
        }
 
        public void RemoveAt(string sourceColumn)
        {
            int index = RangeCheck(sourceColumn);
            RemoveIndex(index);
        }
 
        private void RemoveIndex(int index)
        {
            Debug.Assert((null != _items) && (0 <= index) && (index < Count), "RemoveIndex, invalid");
            _items[index].Parent = null;
            _items.RemoveAt(index);
        }
 
        public void Remove(object? value)
        {
            ValidateType(value);
            Remove((DataColumnMapping)value);
        }
 
        public void Remove(DataColumnMapping value)
        {
            if (null == value)
            {
                throw ADP.ColumnsAddNullAttempt(nameof(value));
            }
            int index = IndexOf(value);
 
            if (-1 != index)
            {
                RemoveIndex(index);
            }
            else
            {
                throw ADP.CollectionRemoveInvalidObject(ItemType, this);
            }
        }
 
        private void Replace(int index, DataColumnMapping newValue)
        {
            Debug.Assert((null != _items) && (0 <= index) && (index < Count), "RemoveIndex, invalid");
            Validate(index, newValue);
            _items[index].Parent = null;
            newValue.Parent = this;
            _items[index] = newValue;
        }
 
        private static void ValidateType([NotNull] object? value)
        {
            if (null == value)
            {
                throw ADP.ColumnsAddNullAttempt(nameof(value));
            }
            else if (!ItemType.IsInstanceOfType(value))
            {
                throw ADP.NotADataColumnMapping(value);
            }
        }
 
        private void Validate(int index, [NotNull] DataColumnMapping? value)
        {
            if (null == value)
            {
                throw ADP.ColumnsAddNullAttempt(nameof(value));
            }
            if (null != value.Parent)
            {
                if (this != value.Parent)
                {
                    throw ADP.ColumnsIsNotParent(this);
                }
                else if (index != IndexOf(value))
                {
                    throw ADP.ColumnsIsParent(this);
                }
            }
 
            string name = value.SourceColumn;
            if (string.IsNullOrEmpty(name))
            {
                index = 1;
                do
                {
                    name = ADP.SourceColumn + index.ToString(System.Globalization.CultureInfo.InvariantCulture);
                    index++;
                } while (-1 != IndexOf(name));
                value.SourceColumn = name;
            }
            else
            {
                ValidateSourceColumn(index, name);
            }
        }
 
        internal void ValidateSourceColumn(int index, string? value)
        {
            int pindex = IndexOf(value);
            if ((-1 != pindex) && (index != pindex))
            { // must be non-null and unique
                throw ADP.ColumnsUniqueSourceColumn(value);
            }
        }
 
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public static DataColumn? GetDataColumn(DataColumnMappingCollection? columnMappings, string sourceColumn, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.PublicFields)] Type? dataType, DataTable dataTable, MissingMappingAction mappingAction, MissingSchemaAction schemaAction)
        {
            if (null != columnMappings)
            {
                int index = columnMappings.IndexOf(sourceColumn);
                if (-1 != index)
                {
                    return columnMappings._items![index].GetDataColumnBySchemaAction(dataTable, dataType, schemaAction);
                }
            }
            if (string.IsNullOrEmpty(sourceColumn))
            {
                throw ADP.InvalidSourceColumn(nameof(sourceColumn));
            }
            switch (mappingAction)
            {
                case MissingMappingAction.Passthrough:
                    return DataColumnMapping.GetDataColumnBySchemaAction(sourceColumn, sourceColumn, dataTable, dataType, schemaAction);
 
                case MissingMappingAction.Ignore:
                    return null;
 
                case MissingMappingAction.Error:
                    throw ADP.MissingColumnMapping(sourceColumn);
            }
            throw ADP.InvalidMissingMappingAction(mappingAction);
        }
 
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public static DataColumnMapping? GetColumnMappingBySchemaAction(DataColumnMappingCollection? columnMappings, string sourceColumn, MissingMappingAction mappingAction)
        {
            if (null != columnMappings)
            {
                int index = columnMappings.IndexOf(sourceColumn);
                if (-1 != index)
                {
                    return columnMappings._items![index];
                }
            }
            if (string.IsNullOrEmpty(sourceColumn))
            {
                throw ADP.InvalidSourceColumn(nameof(sourceColumn));
            }
            switch (mappingAction)
            {
                case MissingMappingAction.Passthrough:
                    return new DataColumnMapping(sourceColumn, sourceColumn);
 
                case MissingMappingAction.Ignore:
                    return null;
 
                case MissingMappingAction.Error:
                    throw ADP.MissingColumnMapping(sourceColumn);
            }
            throw ADP.InvalidMissingMappingAction(mappingAction);
        }
    }
}