C#遍历存储带参构造对象的ArrayList时无法读取对象属性问题
问题核心原因
ArrayList是.NET早期版本提供的非泛型集合,内部所有存储元素都会被视为object类型。你用var遍历集合时,item的编译时类型为object,而object类型并未定义Name属性——你当前能运行并输出类型全限定名,说明实际执行的代码是直接调用Console.WriteLine(item),此时方法会默认调用对象的ToString()实现,而object默认的ToString()方法返回值就是当前实例的类型全限定名。
推荐解决方案
现代C#开发中完全不建议使用ArrayList,应替换为泛型集合List<T>,它会在编译时校验元素类型,遍历取到的元素直接是目标类型,无装箱拆箱性能损耗,也不会出现类型访问错误。
- 首先修改集合定义,注意访问修饰符需要匹配调用场景(Main方法中访问不能设为
private):
// 位于Animal类中 public static List<Animal> AnimalList = new List<Animal>() { Duck.duck1, // 不需要提前定义静态字段,直接new带参构造的自定义对象即可 new Duck("Donald", Gender.Male, 3) };
- 原有遍历逻辑无需修改即可正常运行,此时
item会被自动推断为Animal类型,可直接访问Name属性:
public static void Main() { foreach (var item in AnimalList) Console.WriteLine(item.Name); }
运行后会按预期输出所有动物的Name属性值。
非推荐兼容方案(仅用于必须使用ArrayList的遗留场景)
如果因历史代码约束必须使用ArrayList,遍历元素时需要做显式类型转换,确认类型后再访问属性,避免运行时报错:
public static void Main() { foreach (object rawItem in AnimalList) { if (rawItem is Animal animal) { Console.WriteLine(animal.Name); } } }
相关疑问解答
- 向集合(无论ArrayList还是泛型List)添加带参构造生成的自定义对象,不需要提前定义为静态字段,直接在集合初始化器或调用
Add方法时传入new 类名(构造参数)即可,和普通场景下实例化对象没有区别。 ArrayList并非只能存储string、int等基础类型,它可以存储所有继承自object的类型实例,但因为没有编译时类型约束,很容易混入不符合预期的类型导致运行时错误,加上值类型存储时会产生装箱损耗,在C# 2.0推出泛型之后,所有新编写的业务代码都不应该再使用ArrayList,它目前仅用于兼容2005年之前的老版本.NET遗留代码。- 如果需要自定义类实例直接传入
Console.WriteLine时的输出内容,可以在基类Animal中重写ToString()方法:
public override string ToString() { return Name; }
重写后哪怕不主动访问Name属性,直接输出对象本身也会返回Name值,而不是类型全限定名。
内容的提问来源于stack exchange,提问作者caxap
相关产品推荐
相关产品推荐

