对于你的问题,有几种原生c#的可能性:
动态
数组
IReadOnlyList, IEnumerable
正确使用List<>。
它们都工作得很好!不需要任何复杂的编程!
下面是它们各自的例子:
1. 动态:最通用的解决方案
运行时类型检查
您放弃了编译器错误检查支持,所以要小心处理!如果您尝试添加错误类型的元素,则只会得到一个运行时错误!
您甚至可以分配不相关类的集合。
简单写动态listOfA = new List<C>();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的实例。
You can exchange elements, but you can't remove or add new elements.
Trying to set a wrong type yields a runtime error.
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:
Assign your List<C> to an IEnumerable<A> or IReadOnlyList<A>
Neither of them can be changed at runtime, i.e. you can't Add or Remove elements.
Why should the compiler allow assigning your List<C> to a List<A> instead of IReadOnlyList<A> when adding an element will lead to an error anyway?
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>()
Define a List of your interface
Assign instances of one derived class only - you didn't want to store other classes anyway, did you?
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!!!