1. IReadOnlyList和IEnumerable:这可能是你需要的
- 两者都不能在运行时更改,即你无法添加或删除元素。
- 你仍然可以修改数据元素本身。
- 使用这个IEnumerable或IReadOnlyList非常便宜,只需通过另一个指针访问数据。
- 但要小心:如果你向IEnumerable或IReadOnlyList附加元素,那么你会创建一个新的IEnumerable。不正确地使用这个IEnumerable可能会变得昂贵。
由于没有元素可以添加,因此所有元素保持正确的类型:
public static void TestIEnumerableAndIReadonlyList()
{
var cats = new List<Cat>()
{
new Cat() { CatName = "Cat-3" },
};
IEnumerable<IAnimal> animalsEnumerable = cats;
IReadOnlyList<IAnimal> animalsReadOnlyList = cats;
var extendedEnumerable = animalsReadOnlyList.Append(new Bear());
(extendedEnumerable.First() as Cat).CatName = "Cat-3a";
Console.WriteLine("Cat names: {0}, {1}, {2}, {3}",
cats.ElementAt(0).CatName,
animalsReadOnlyList[^1].Name,
AnyName(animalsEnumerable.Last()),
AnyName(extendedEnumerable.ElementAt(1)));
}
2. 合理使用 List<>
: List<A> listOfA = new()
- 定义一个接口的List(而不是派生类)
- 只分配一个派生类的实例 - 你也不想存储其他类,对吗?
将一只猫添加到一个应该是熊的动物列表中:
public static void TestListOfInterface()
{
var bears = new List<IAnimal>()
{
new Bear() { BearName = "Bear-1" },
};
bears.Add(new Cat() { CatName = "Cat-2" });
string bearNames = string.Join(", ", bears.Select(animal => animal.Name));
Console.WriteLine($"Bear names: {bearNames}");
static string VerifyBear(IAnimal bear)
=> (bear as Bear)?.Name ?? "disguised as a bear!!!";
string bearInfo0 = VerifyBear(bears[0]);
string bearInfo1 = VerifyBear(bears[1]);
Console.WriteLine($"One animal is {bearInfo0}, the other one is {bearInfo1}");
}
3. 数组
:创建一个Bear[]
数组,保证所有的数组元素都引用了Bear
实例。
- 您可以交换元素,但不能删除或添加新元素。
- 尝试设置错误的类型会导致运行时错误。
数组中的熊:
public static void TestArray()
{
Bear[] bears = { new Bear(), null };
IAnimal[] bearAnimals = bears;
try { bearAnimals[1] = new Cat(); }
catch (Exception e) { Console.Error.WriteLine(e); }
bearAnimals[1] = new Bear() { BearName = "Bear-2" };
Console.WriteLine($"Bear names: {bearAnimals[0].Name}, {bears[1].BearName}");
}
4. dynamic
和 List<dynamic>
: 最通用的解决方案
- 运行时类型检查。
- 您放弃了编译器的错误检查支持,因此请小心处理!
- 如果您尝试添加错误类型的元素,则只会获得运行时错误!
- 如果您访问不存在的成员,则只会获得运行时错误!
- 您甚至可以分配不相关类的集合。
将列表分配给dynamic
或使用List<dynamic>
:
public static void TestDynamicListAndArray()
{
dynamic any = new List<Cat>()
{
new Cat() { CatName = "Cat-1" },
new Cat() { CatName = "Cat-2" },
};
try { any[0].BearName = "Bear-1"; }
catch (Exception e) { Console.Error.WriteLine(e); }
try { any.Add(new Bear()); }
catch (Exception e) { Console.Error.WriteLine(e); }
any[1].CatName += 'a';
Console.WriteLine($"Animal names: {any[0].CatName}, {any[1].Name}");
var mix = new List<dynamic>
{
new Bear() {BearName = "Bear-3"},
new Dog() {DogName = "Dog-4"},
"Cat-5",
};
Console.WriteLine($"{AnyName(mix[0])}, {mix[1].Name}, {AnyName(mix[2])}");
try { Console.WriteLine($"Names: {any[2].Name}"); }
catch (Exception e) { Console.Error.WriteLine(e); }
any = new Bear() { BearName = "Bear-6" };
try { Console.WriteLine($"{AnyName(any[0])}"); }
catch (Exception e) { Console.Error.WriteLine(e); }
}
}