C#-用于保存从同一基类继承的多个对象类型的列表
在下面的示例中,我希望能够将StandardCar或RaceCar的实例放入CarCollection列表中,然后在循环CarCollection列表时将它们转换为正确的数据类型 我知道这在C#中是不可能的。但是我找不到一种不涉及一个类的方法,该类在一个类中具有所有属性。既然NumberOfRaces只适用于赛车,那么这样做看起来有点混乱吗 当我在收集中循环时,我就会知道我是在使用标准车还是赛车。但目前,使用下面的代码,如果我将StandardCar放入列表中,然后循环该列表并将其转换为StandardCar,我将得到一个转换异常 请注意,我实际的最后一堂课比下面的要复杂得多C#-用于保存从同一基类继承的多个对象类型的列表,c#,list,oop,C#,List,Oop,在下面的示例中,我希望能够将StandardCar或RaceCar的实例放入CarCollection列表中,然后在循环CarCollection列表时将它们转换为正确的数据类型 我知道这在C#中是不可能的。但是我找不到一种不涉及一个类的方法,该类在一个类中具有所有属性。既然NumberOfRaces只适用于赛车,那么这样做看起来有点混乱吗 当我在收集中循环时,我就会知道我是在使用标准车还是赛车。但目前,使用下面的代码,如果我将StandardCar放入列表中,然后循环该列表并将其转换为Stan
class Car
{
public string Name {get; set;}
}
class RaceCar : Car
{
public int NumberOfRaces {get; set;}
}
class StandardCar: Car
{
public bool ChildrenInCar {get; set;}
}
class CarCollection
{
List<Car> Collection {get; set;}
}
等级车
{
公共字符串名称{get;set;}
}
级别赛车:赛车
{
公共int NumberOfRaces{get;set;}
}
等级标准车:汽车
{
公共bool childreneinvo{get;set;}
}
分类收集
{
列表集合{get;set;}
}
感谢您的帮助。创建一个界面:
public interface ICar{
//Place all common property / method definitions here
}
public class Car : ICar
{
//implementation
}
使Car实现该接口:
public interface ICar{
//Place all common property / method definitions here
}
public class Car : ICar
{
//implementation
}
然后更改您的汽车收藏:
public class CarCollection
{
List<ICar> Collection{get; set;}
}
公共类CarCollection
{
列表集合{get;set;}
}
现在,您应该能够将任何具有汽车底座的内容添加到该列表中。枚举集合时,所有ICAR都将在界面中定义这些属性/方法,您无需强制转换和类型检查即可访问这些属性/方法。创建一个界面:
public interface ICar{
//Place all common property / method definitions here
}
public class Car : ICar
{
//implementation
}
使Car实现该接口:
public interface ICar{
//Place all common property / method definitions here
}
public class Car : ICar
{
//implementation
}
然后更改您的汽车收藏:
public class CarCollection
{
List<ICar> Collection{get; set;}
}
公共类CarCollection
{
列表集合{get;set;}
}
现在,您应该能够将任何具有汽车底座的内容添加到该列表中。枚举集合时,所有ICAR都将在界面中定义这些属性/方法,您可以访问这些属性/方法,而无需强制转换和类型检查。是的,您可以将
StandardCar
添加到List
集合中。您不能做的是在迭代集合时轻松访问派生类特定的属性
var collection = new CarCollection();
collection.Collection= new List<Car>();
collection.Collection.Add(new RaceCar());
collection.Collection.Add(new StandardCar());
foreach (var car in collection.Collection)
Console.WriteLine(car.Name);
由于
childreneinbo
仅存在于StandardCar
是,您可以将StandardCar
添加到列表
集合中。您不能做的是在迭代集合时轻松访问派生类特定的属性
var collection = new CarCollection();
collection.Collection= new List<Car>();
collection.Collection.Add(new RaceCar());
collection.Collection.Add(new StandardCar());
foreach (var car in collection.Collection)
Console.WriteLine(car.Name);
由于
childreneinbo
仅存在于StandardCar
中,因此完全可以正常添加到列表中,但要返回,需要测试返回的汽车类型:
// Create the cars
RaceCar rcar = new RaceCar();
StandardCar scar = new StandardCar();
// Add to the collection
CarCollection col = new CarCollection();
col.Add(rcar);
col.Add(scar);
// Iterate
foreach(Car car in col.Collection)
{
if(car is RaceCar)
{
RaceCar racecar = (RaceCar)car;
}
else if(car is StandardCar)
{
StandardCar standCar = (StandardCar)car;
}
// ... etc
}
你也可以这样做:
car as RaceCar
并确保返回的值不为null
注意:代码未经测试,但应能正常工作。完全有可能,您可以正常添加到列表中,但要返回,需要测试返回的车辆类型:
// Create the cars
RaceCar rcar = new RaceCar();
StandardCar scar = new StandardCar();
// Add to the collection
CarCollection col = new CarCollection();
col.Add(rcar);
col.Add(scar);
// Iterate
foreach(Car car in col.Collection)
{
if(car is RaceCar)
{
RaceCar racecar = (RaceCar)car;
}
else if(car is StandardCar)
{
StandardCar standCar = (StandardCar)car;
}
// ... etc
}
你也可以这样做:
car as RaceCar
并确保返回的值不为null
注意:代码未经测试,但应该可以工作。您可以检测强制转换是否工作:
List<Car> Collection;
..
foreach (Car car in Collection)
{
RaceCar raceCar = car as RaceCar;
if (raceCar != null)
{
raceCar.NumberOfRaces++;
}
}
然后RaceCar会有自己的Update()实现,它会处理NumberOfRaces。此外,您可能不需要NumberOfRaces属性来设置一个setter,甚至可能不需要将其公开。您可以检测强制转换是否有效:
List<Car> Collection;
..
foreach (Car car in Collection)
{
RaceCar raceCar = car as RaceCar;
if (raceCar != null)
{
raceCar.NumberOfRaces++;
}
}
然后RaceCar会有自己的Update()实现,它会处理NumberOfRaces。此外,您可能不需要NumberOfRaces属性具有setter,甚至可能不需要将其公开。处理此问题的方法多种多样。只要有可能,你应该尽量避免铸造的需要。例如,如果要以不同的方式显示不同的车辆,请覆盖
ToString
方法。您还可以添加以不同方式响应不同情况的方法。在基类中将这些方法声明为抽象的(同时也将基类声明为抽象的)
另一种可能性是测试实际类型:
if (car is RaceCar) {
((RaceCar)car).NumberOfRaces++;
} else if (car is StandardCar) {
((StandardCar)car).ChildrenInCar = 0;
}
另一种可能性是过滤车型并单独处理:
var raceCars = cars.OfType<RaceCar>();
foreach (raceCar in raceCars) {
raceCar.NumberOfRaces++;
}
var raceCars=cars.OfType();
foreach(赛车中的赛车){
赛车。NumberOfRaces++;
}
处理此问题有不同的可能性。只要有可能,你应该尽量避免铸造的需要。例如,如果要以不同的方式显示不同的车辆,请覆盖ToString
方法。您还可以添加以不同方式响应不同情况的方法。在基类中将这些方法声明为抽象的(同时也将基类声明为抽象的)
另一种可能性是测试实际类型:
if (car is RaceCar) {
((RaceCar)car).NumberOfRaces++;
} else if (car is StandardCar) {
((StandardCar)car).ChildrenInCar = 0;
}
另一种可能性是过滤车型并单独处理:
var raceCars = cars.OfType<RaceCar>();
foreach (raceCar in raceCars) {
raceCar.NumberOfRaces++;
}
var raceCars=cars.OfType();
foreach(赛车中的赛车){
赛车。NumberOfRaces++;
}
另一种设计是使用接口指定不同汽车对象的不同逻辑边界
interface ICar ...
interface IRacingCar : ICar
interface IFlyingCar : ICar
interface IFamilyCar : ICar
然后在你的循环中,你根据各种汽车的逻辑能力对它们进行操作
void ProcessCars()
{
foreach( var car in cars )
{
if(car is IRacingCar) ...
if(car is IFlyingCar) ...
if(car is IFamilyCar) ...
}
}
这种方法的优点是,您可以拥有更多类型的类,而不必为每个类都使用if语句。此外,您的if语句一次只需要处理一个问题
class RaceCar: IRacingCar ...
class FlyingRaceCar: IRaceCar, IFlyingCar ...
class FlyingFamilyCar: IFlyingCar, IFamilyCar ...
这个循环并不关心一辆车可以实现多个接口。它一次只需要处理一个问题
例如,任何一辆汽车都可以应对重力和空中交通管制,而不管它是否有儿童乘客或完成了多少场比赛
这就是接口的优点。它们允许界面的使用者只关心对象的质量。另一种设计是使用界面指定不同汽车对象的不同逻辑边界
interface ICar ...
interface IRacingCar : ICar
interface IFlyingCar : ICar
interface IFamilyCar : ICar
然后在您的循环中对var进行操作