1
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

.NET Coreのソースを読む!第一回 List<T> パート2

Last updated at Posted at 2018-05-05

はじめに

.NET Coreのソースを読む!第一回 List パート1の続きです。

ソースリンク

ソースを読む!

プロパティ

        public int Capacity
        {
            get
            {
                return _items.Length;
            }
            set
            {
                if (value < _size)
                {
                    ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value, ExceptionResource.ArgumentOutOfRange_SmallCapacity);
                }

                if (value != _items.Length)
                {
                    if (value > 0)
                    {
                        T[] newItems = new T[value];
                        if (_size > 0)
                        {
                            Array.Copy(_items, 0, newItems, 0, _size);
                        }
                        _items = newItems;
                    }
                    else
                    {
                        _items = s_emptyArray;
                    }
                }
            }
        }

Capacityは、List内部で保持している配列の長さになりますね。Listの長さではなく、内部でデータを実際に格納している配列の長さです。Addしていって、Capacityを超えそうになったら、自動で拡張するようになっていますね。前回も記載しましたが、最初からデータ量が多いと分かっている場合は、Capacityをコンストラクタで指定するのが定石ですね。

「_size」が実際のデータの長さなので、それを超える場合は、エラーにするのですね。そもそも、Listのインスタンスを作成した後に、Capacityが変えれるのは知りませんでした。Capacityを変えると、内部で新たな配列を作成するので、ちゃんと理解しておかないといけませんね。

valueに0が指定されたら「s_emptyArray」をちゃんと初期化時に使っていますね。共通ライブラリなので、少しでもメモリを節約する努力だと思うのですが、どこの誰が、Capacityに0を指定するのでしょうね。。。

        // Read-only property describing how many elements are in the List.
        public int Count => _size;

これで「_size」の値を読み取り専用で公開できるのですね。
6.0からの機能で、「expression-bodied function member」というのですね。
私の現場では、5.0なので、これは使ったことありません。

しかし、公開はCountで、内部は_sizeってのはなんででしょうか?
最初に_sizeにしちゃって、変えようと思ったら、シリアライズ対策のために変えれなかったのかな。
あと、IListではCountプロパティで、LINQにもCountメソッド(拡張メソッドだけど)があるから紛らわしいですね。

        bool IList.IsFixedSize => false;
        bool ICollection<T>.IsReadOnly => false;
        bool IList.IsReadOnly => false;
        bool ICollection.IsSynchronized => false;

Listは、固定長ではなく、読み取り専用でもなく、スレッドセーフでもないということですね。

おお、bool IList.IsFixedSize => false;みたいに、特定のインタフェースで参照したときしか参照できない方法でオーバーライドしてますね。IList.IsFixedSizeとすると、IListインタフェースで参照したときしか、IsFixedSizeプロパティが参照できなくなりますね。
しかし、このC#の機能は私は一度も使ったことがないのですが、標準ライブラリではガンガン使っているのですね。

        object ICollection.SyncRoot
        {
            get
            {
                if (_syncRoot == null)
                {
                    Interlocked.CompareExchange<object>(ref _syncRoot, new object(), null);
                }
                return _syncRoot;
            }
        }

SyncRootプロパティは、誰かが同期処理をするときに使うのかな?使ったことないけど。

Interlocked.CompareExchangeは、便利そうですね。詳細は、以下の「(4) 値を比較し、等しければ指定した別の値を代入する」に説明がありました。

ロックして、値を初期化するときに便利そうですが、逆に分かりにくいかもしれませんね。

        public T this[int index]
        {
            get
            {
                // Following trick can reduce the range check by one
                if ((uint)index >= (uint)_size)
                {
                    ThrowHelper.ThrowArgumentOutOfRange_IndexException();
                }
                return _items[index];
            }

            set
            {
                if ((uint)index >= (uint)_size)
                {
                    ThrowHelper.ThrowArgumentOutOfRange_IndexException();
                }
                _items[index] = value;
                _version++;
            }
        }

インデクサーですね。
範囲外の場合はエラーにしますね。
インデクサーでは自動で拡張してくれませんよ!!お気をつけて。
自動で拡張するのはAddメソッドでっせ。

        object IList.this[int index]
        {
            get
            {
                return this[index];
            }
            set
            {
                ThrowHelper.IfNullAndNullsAreIllegalThenThrow<T>(value, ExceptionArgument.value);

                try
                {
                    this[index] = (T)value;
                }
                catch (InvalidCastException)
                {
                    ThrowHelper.ThrowWrongValueTypeArgumentException(value, typeof(T));
                }
            }
        }

おお、Genericではない型で参照されたときのインデクサーの実装は、分けているのですね。

次回はスタティックメソッドかな。

ライセンス

色々ソースを載せているので、念のためライセンスへリンクしておきます。

1
5
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?