C#中如何实现可存储多类型元素的数组
C#是强类型语言,数组、泛型集合默认要求指定统一的元素类型,确实不能像JS、Python那样直接定义无类型约束的数组,但有几种成熟的变通方案可以实现多类型同存的需求,各有适用场景:
方案1:声明
object类型数组
C#里所有类型,不管是int、bool这类值类型,还是string、自定义类这类引用类型,都直接或间接继承自object基类,所以声明object类型的数组就能存入任意类型的元素,是最通用的实现方式。// 初始化时直接放入不同类型元素 object[] myArray = new object[] { "foo", "bar", 123, true, new MyCustomObject() }; // 读取元素时需要显式做类型转换 string firstStr = (string)myArray[0]; int numVal = (int)myArray[2];要注意的是,值类型存入object数组时会发生装箱,读取时拆箱,有少量性能开销;如果类型转换不匹配,运行时会直接抛出
InvalidCastException,没有编译期提示,读取元素时最好先用is运算符或者模式匹配校验类型,避免强转失败。方案2:使用
dynamic动态类型数组
C# 4.0新增的dynamic类型会跳过编译期的类型检查,所有类型解析逻辑都放到运行时执行,也可以用来存多类型元素:dynamic[] myArray = new dynamic[] { "foo", "bar", 123, true, new MyCustomObject() }; // 读取时不需要手动写强转代码,运行时会自动匹配类型成员 int strLength = myArray[0].Length; // 可以直接调用字符串的Length属性这个方案的缺点很明显:完全没有编译期类型校验,哪怕你写了根本不存在的属性、方法,编译阶段也不会报错,只有跑到对应代码的时候才会抛异常,项目大了很容易出隐蔽bug,非特殊场景不推荐用。
方案3:用非泛型集合
ArrayList(仅兼容老版本.NET场景)
在泛型特性推出之前,.NET提供的ArrayList本质就是内部封装了一个动态扩容的object数组,不需要提前指定长度,也支持存入任意类型元素:using System.Collections; ArrayList myList = new ArrayList(); myList.Add("foo"); myList.Add(123); myList.Add(true);这个集合和直接用object数组的问题完全一致:有装箱拆箱开销、无编译期类型安全,现在新写的项目不推荐用,只有维护老.NET Framework项目的时候可以按需使用。
如果业务场景里你明确知道数组只会存固定的几种类型(比如只会存string、int、bool三类),处理元素时配合模式匹配做分支处理就好,比无限制的任意类型存储可控性高很多,能减少不少运行时异常。
内容的提问来源于stack exchange,提问作者c136

