最近、C#を学び始めました。
コードを書いているときに、引数にList型を持たせた関数を作成した際、以下のように書きました。
public void Test(List<int> testList)
{
foreach (var list in testList)
{
Console.WriteLine($@"{list}");
}
}
しかし、これだと関数内でListの中の値が変更可能と知り、C++のconstのように関数内では変更できなくするようなものがないか調べました。使用環境は以下の通りです。
使用環境
- Visual Studio Community 2017
- .NET Framework 4.6.1
- C# 7.1
IEnumerable<T>
指定した型のコレクションに対する単純な反復処理をサポートする列挙子を公開します。
引用先 IEnumerable(T) インターフェイス (System.Collections.Generic)
pubilc void Test(IEnumerable<int> testList)
{
foreach (var list in testList)
{
Console.WriteLine($@"{list}");
}
}
内部でforeach文などを使用するときには便利だと感じました。しかし、関数内ではindex指定して値が得られませんでした。
pubilc void Test(IEnumerable<int> testList)
{
//エラー
var number = testList[0];
}
IReadOnlyList<T>
インデックスによってアクセスできる要素の読み取り専用コレクションを表します。
引用先 IReadOnlyList(T) インターフェイス (System.Collections.Generic)
pubilc void Test(IReadOnlyList<int> testList)
{
foreach (var list in testList)
{
Console.WriteLine($@"{list}");
}
}
IReadOnlyList<T>はインデックス指定で値を得られました。関数内でも配列と同様に扱えるのは便利ですね。
pubilc void Test(IReadOnlyList<int> testList)
{
//正常に動作する
var number = testList[0];
}
感想
個人的な感想としては、IReadOnlyList<T>の方が、C++のconstに近いのかなと感じました。
ただ、両方ともキャスト変換すれば値が変更できますが、その点を考慮しなければ十分読み取り専用として使用できそうです。
pubilc void Test(IEnumerable<int> testList)
{
//キャスト変換により値が変更可能
((List<int>)testList)[0] = 100;
}
pubilc void Test(IReadOnlyList<int> testList)
{
//キャスト変換により値が変更可能
((List<int>)testList)[0] = 200;
}
あと、余談でIReadOnlyList<T>はCountプロパティが使える点が IEnumerable<T>よりも優れていると思います。
他にもあれば情報提供よろしくお願いします。
追記
sdkeiさんからの情報提供で、変更可能な方にキャストできなくするには、List.AsReadOnly メソッドを使用して ReadOnlyCollection 型のオブジェクトにすればいいという意見をもらいました。
public void Main()
{
var readOnlyLists = new List<int>() { 1, 2, 3};
//ReadOnlyCollection<T>オブジェクトにする
Test(readOnlyLists.AsReadOnly());
}
pubilc void Test(IReadOnlyList<int> testList)
{
//エラー
//実行時,System.InvalidCastExceptionが発生する
((List<int>)testList)[0] = 200;
}