对于您的问题,有几种原生C# 可能性:
dynamic
Array
IReadOnlyList
,IEnumerable
使用List<>
正确的方法。
他们都运作良好!不需要任何棘手的编程!
以下是每个示例:
1 dynamic
.:最通用的解决方案
- 运行时类型检查
- 你放弃了你的编译器错误检查支持,所以要小心处理!如果你尝试添加一个错误类型的元素,你只会得到一个运行时错误!
- 您甚至可以分配不相关类的集合。
简单地写dynamic listOfA = new List<C>();
而不是List<A> listOfA = new List<C>();
首先是所有示例的接口和类定义:
using System;
using System.Collections.Generic;
using System.Linq;
interface IAnimal
{
public string Name { get; }
}
class Bear : IAnimal
{
public string BearName = "aBear";
public string Name => BearName;
}
class Cat : IAnimal
{
public string CatName = "aCat";
public string Name => CatName;
}
// Dog has no base class/interface; it isn't related to the other classes
class Dog
{
public string DogName = "aDog";
public string Name => DogName;
}
这是使用的示例dynamic
public class AssignDerivedClass
{
public static void TestDynamicListAndArray()
{
dynamic any = new List<Bear>() // List of derived
{
new Bear() { BearName = "Bear-1" },
new Bear() { BearName = "Bear-2" }
};
//any[0].CatName = "NewCat"; // => Microsoft.CSharp.RuntimeBinder.RuntimeBinderException
Console.WriteLine($"Bear names: {any[0].BearName}, {Name(any[1])}");
any = new Cat[] // Array of derived
{
new Cat() { CatName = "Cat-3" },
new Cat() { CatName = "Cat-4" }
};
Console.WriteLine($"Cat names: {any[0].CatName}, {any[1].Name}");
any = new List<Dog>() // List of non-related class
{
new Dog() { DogName = "Dog-5" },
new Dog() { DogName = "Dog-6" }
};
Console.WriteLine($"Dog names: {any[0].DogName}, {Name(any[1])}");
any = new List<IAnimal>() // List of interface
// any = new IAnimal[] // Array of interface works the same
{
new Bear() { BearName = "Bear-7" },
new Cat() { CatName = "Cat-8" }
};
Console.WriteLine($"Animal names: {any[0].BearName}, {any[1].CatName}");
any[0].BearName = "NewBear";
Console.WriteLine($"Animal names: {Name(any[0])}, {any[1].Name}");
}
private static string Name(dynamic anymal)
{
return anymal switch
{
Bear bear => bear.BearName,
Cat cat => cat.CatName,
Dog dog => dog.DogName,
_ => "No known Animal"
};
}
// Bear names: Bear-1, Bear-2
// Cat names: Cat-3, Cat-4
// Dog names: Dog-5, Dog-6
// Animal names: Bear-7, Cat-8
// Animal names: NewBear, Cat-8
}
2. Array
: 创建Bear[]
数组,保证所有数组元素引用Bear
.
您可以交换元素,但不能删除或添加新元素。
尝试设置错误的类型会产生运行时错误。
public static void TestArray()
{
Bear[] bears = { new Bear(), null };
IAnimal[] bearAnimals = bears;
//bearAnimals[1] = new Cat(); // System.ArrayTypeMismatchException
bearAnimals[1] = new Bear() { BearName = "Bear-1" };
Console.WriteLine($"Bear names: {bearAnimals[0].Name}, {bears[1].BearName}");
}
// Result => Bear names: aBear, Bear-1
3. IReadOnlyList
,IEnumerable
:
将您分配List<C>
给一个IEnumerable<A>
或IReadOnlyList<A>
它们都不能在运行时更改,即您不能添加或删除元素。
为什么编译器应该允许将您分配List<C>
给 aList<A>
而不是IReadOnlyList<A>
在添加元素时会导致错误?
public static void TestIEnumerableAndIReadonlyList()
{
var cats = new List<Cat>()
{
new Cat() { CatName = "Cat-3" },
new Cat() { CatName = "Cat-4" }
};
IEnumerable<IAnimal> iEnumerable = cats;
Console.WriteLine($"Cat names: {(iEnumerable.ElementAt(0) as Cat).CatName}, "
+ Name(iEnumerable.Last()));
IReadOnlyList<IAnimal> iROList = cats;
Console.WriteLine($"Cat names: {iROList[0].Name}, {Name(iROList[1])}");
//iROList.Add(new Cat()); // compiler error CS61: no definition for 'Add'
}
// Result:
// Cat names: Cat-3, Cat-4
// Cat names: Cat-3, Cat-4
4.使用List<>
正确的方法: List<A> listOfA = new List<A>()
定义你的接口列表
只分配一个派生类的实例——你不想存储其他类,是吗?
public static void TestListOfInterface()
{
var bears = new List<IAnimal>()
{
new Bear() { BearName = "Bear-1" },
new Cat() { CatName = "Cat-3" },
};
bears.Add(new Bear() { BearName = "Bear-2" });
string bearNames = string.Join(", ", bears.Select(animal => animal.Name));
Console.WriteLine($"Bear names: {bearNames}");
string bearInfo0 = VerifyBear(bears[0]);
string bearInfo1 = VerifyBear(bears[1]);
Console.WriteLine($"One animal is {bearInfo0}, the other one is {bearInfo1}");
string VerifyBear(IAnimal bear)
=> (bear as Bear)?.BearName ?? "disguised as a bear!!!";
}
// Bear names: Bear-1, Cat-3, Bear-2
// One animal is Bear-1, the other one is disguised as a bear!!!