在 C# 中使用基 class 和派生 classes 实例化数组中的对象
Instantiating objects in an array using base class and derived classes in C#
我正在尝试为 "Sport" 抽象 class 的 10 名运动员数组实例化对象,其中包含每个运动员的姓名和年龄,然后有两个派生的 class es 一份给 "Tennis" 名运动员,另一份给 "Golf" 名运动员。
class Program
{
static void Main(string[] args)
{
Sport[] athlete = new Sport[10];
athlete[0] = new Tennis("John Smith", 18, "Tennis", 5.0, 92);
athlete[1] = new Tennis("Lisa Townsend", 15, "Tennis");
athlete[2] = new Tennis("Brian Mills", 17, "Tennis", 4.0, 83);
athlete[3] = new Golf("Stacey Bell", 16, "Golf", 10, 20);
athlete[4] = new Golf("Tom Spehr", 18, "Golf", 9, 12);
athlete[5] = new Golf("Sam Calen", 14, "Golf");
athlete[6] = new Tennis("Karen Strong", 17, "Tennis", 3.0, 78);
athlete[7] = new Golf("Ken Able", 15, "Golf", 15, 16);
athlete[8] = new Tennis("Troy Soni", 18, "Tennis", 4.5, 93);
athlete[9] = new Golf("Toni Palmer", 17, "Golf", 8, 22);
for (int i = 0; i < 10; i++)
{
Console.WriteLine("{0}", athlete[i]);
}
}
}
我正尝试像这样打印数组,但输出不正确。此外,当我尝试将数据字段单独打印为
Console.WriteLine("{0} {1}", 运动员[i].name, 运动员[i].age)
我可以让它输出每个运动员的姓名和年龄,但如果我尝试添加其他字段,它们将不会输出。我应该将每个数组对象声明为 "Sport" 而不是网球或高尔夫吗?
编辑:
这是运动class
abstract class Sport
{
protected string name;
protected int age;
public Sport(string name, int age)
{
Name = name;
Age = age;
}
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
public int Age
{
get
{
return age;
}
set
{
age = value;
}
}
public abstract void Performance();
}
这里是派生的 Tennis class(高尔夫 class 的结构与此相同,只是对变量名称稍作更改)
class Tennis : Sport
{
private string type;
private double rating;
private int serveSpeed;
public Tennis(string name, int age, string type, double rating, int serveSpeed) : base(name, age)
{
Rating = rating;
Type = type;
ServeSpeed = serveSpeed;
}
public Tennis(string name, int age, string type) : base(name, age)
{
}
public double Rating
{
get
{
return rating;
}
set
{
rating = value;
}
}
public string Type
{
get
{
return type;
}
set
{
type = "Tennis";
}
}
public int ServeSpeed
{
get
{
return serveSpeed;
}
set
{
serveSpeed = value;
}
}
如果我正确理解你的问题,你希望能够为你的 classes 输出一个友好的字符串,它们总是输出 Name
和 Age
,然后为每项运动他们输出该运动的特定属性。
这可以通过覆盖 ToString
属性 来完成。您可以在 Name
和 Age
的基础 class 中执行此操作,然后在每个单独的 class 中,您可以输出 base.ToString
以及任何特定的 [=36] =]属性。
例如,基础 class 将输出姓名和年龄:
abstract class Sport
{
public override string ToString()
{
return string.Format("{0} {1}", Name, Age);
}
// Rest of class code omitted...
网球class也会输出一些其他字段:
class Tennis : Sport
{
public override string ToString()
{
return string.Format("{0} [Sport: {1}] [Rating: {2}] [Serve Speed: {3}]",
base.ToString(), Type, Rating, ServeSpeed);
}
// Rest of class code omitted...
那么您的输出将如下所示:
另外,请注意 Sport
字符串对于 Lisa Townsend
是空的,因为用于实例化该实例的构造函数没有设置 Type
属性。
让我们来解决这一切。现在是您在 C# 职业生涯中学习良好习惯和做法的时候了。
abstract class Sport
运动?不,这个 class 不代表 运动 。这个 class 代表 玩家 。运动就是他们玩的。您在 Main
中将本地命名为 "athlete" 的事实告诉您您在这里犯了一个错误。称其为 Athlete
或 Player
或其他名称。假设 Player
,因为这样派生的 classes 可以是 TennisPlayer
和 GolfPlayer
或 Golfer
.
protected string name;
protected int age;
为什么要保护?你有 public getters 和 setters 包装这些!
完全消除支持字段。
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
这些都是不必要的罗嗦;使用自动属性。
public int Age
时代在不断变化;生日没有。存储生日,然后查看
How to calculate an age based on a birthday?
public abstract void Performance();
我不知道这是什么意思,但它可能是错误的。抽象方法通常是动词,但这是一个名词。这不应该是Perform
吗?或 Play
?您从派生的 classes 中省略了它,所以让我们忽略它。
我们还想说说我们玩什么运动。因此,让我们为此创建一个类型。放在一起:
enum Sport { Tennis, Golf }
public abstract class Player
{
// Consider making Name and Birthday get-only as well.
// Is there any situation in which they change after construction?
// If not, then *don't allow them to change*!
public string Name { get; set; }
public DateTime Birthday { get; set; }
public abstract Sport Sport { get; }
public Player(string name, DateTime birthday)
{
this.Name = name;
this.Birthday = birthday;
}
}
更短更容易理解。现在让我们推导出一些类型。我们将再次缩短属性,并添加一个 ToString。
另外,Rating
真的是double吗?对身高或体重等物理量使用双打。我怀疑这是 decimal,而不是 double。如果将 3.4 的评级实际存储为 3.39999999999999999 是绝对错误的,那么双精度是错误的类型,小数是正确的类型。
public sealed class TennisPlayer : Player
{
public override Sport Sport => Sport.Tennis;
// Again, do these change after construction? If not
// then remove the setters.
public decimal Rating { get; set; }
public int ServeSpeed { get; set; }
public TennisPlayer(string name, DateTime birthday, decimal rating, int speed) : base(name, birthday)
{
this.Rating = rating;
this.ServeSpeed = speed;
}
public override string ToString()
{
return @"Tennis player: {Name} {Birthday} {Rating} {ServeSpeed}";
}
}
同样,更短更易于阅读。现在你对 GolfPlayer
或 Golfer
或任何你称之为的东西做同样的事情。
我正在尝试为 "Sport" 抽象 class 的 10 名运动员数组实例化对象,其中包含每个运动员的姓名和年龄,然后有两个派生的 class es 一份给 "Tennis" 名运动员,另一份给 "Golf" 名运动员。
class Program
{
static void Main(string[] args)
{
Sport[] athlete = new Sport[10];
athlete[0] = new Tennis("John Smith", 18, "Tennis", 5.0, 92);
athlete[1] = new Tennis("Lisa Townsend", 15, "Tennis");
athlete[2] = new Tennis("Brian Mills", 17, "Tennis", 4.0, 83);
athlete[3] = new Golf("Stacey Bell", 16, "Golf", 10, 20);
athlete[4] = new Golf("Tom Spehr", 18, "Golf", 9, 12);
athlete[5] = new Golf("Sam Calen", 14, "Golf");
athlete[6] = new Tennis("Karen Strong", 17, "Tennis", 3.0, 78);
athlete[7] = new Golf("Ken Able", 15, "Golf", 15, 16);
athlete[8] = new Tennis("Troy Soni", 18, "Tennis", 4.5, 93);
athlete[9] = new Golf("Toni Palmer", 17, "Golf", 8, 22);
for (int i = 0; i < 10; i++)
{
Console.WriteLine("{0}", athlete[i]);
}
}
}
我正尝试像这样打印数组,但输出不正确。此外,当我尝试将数据字段单独打印为
Console.WriteLine("{0} {1}", 运动员[i].name, 运动员[i].age)
我可以让它输出每个运动员的姓名和年龄,但如果我尝试添加其他字段,它们将不会输出。我应该将每个数组对象声明为 "Sport" 而不是网球或高尔夫吗?
编辑:
这是运动class
abstract class Sport
{
protected string name;
protected int age;
public Sport(string name, int age)
{
Name = name;
Age = age;
}
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
public int Age
{
get
{
return age;
}
set
{
age = value;
}
}
public abstract void Performance();
}
这里是派生的 Tennis class(高尔夫 class 的结构与此相同,只是对变量名称稍作更改)
class Tennis : Sport
{
private string type;
private double rating;
private int serveSpeed;
public Tennis(string name, int age, string type, double rating, int serveSpeed) : base(name, age)
{
Rating = rating;
Type = type;
ServeSpeed = serveSpeed;
}
public Tennis(string name, int age, string type) : base(name, age)
{
}
public double Rating
{
get
{
return rating;
}
set
{
rating = value;
}
}
public string Type
{
get
{
return type;
}
set
{
type = "Tennis";
}
}
public int ServeSpeed
{
get
{
return serveSpeed;
}
set
{
serveSpeed = value;
}
}
如果我正确理解你的问题,你希望能够为你的 classes 输出一个友好的字符串,它们总是输出 Name
和 Age
,然后为每项运动他们输出该运动的特定属性。
这可以通过覆盖 ToString
属性 来完成。您可以在 Name
和 Age
的基础 class 中执行此操作,然后在每个单独的 class 中,您可以输出 base.ToString
以及任何特定的 [=36] =]属性。
例如,基础 class 将输出姓名和年龄:
abstract class Sport
{
public override string ToString()
{
return string.Format("{0} {1}", Name, Age);
}
// Rest of class code omitted...
网球class也会输出一些其他字段:
class Tennis : Sport
{
public override string ToString()
{
return string.Format("{0} [Sport: {1}] [Rating: {2}] [Serve Speed: {3}]",
base.ToString(), Type, Rating, ServeSpeed);
}
// Rest of class code omitted...
那么您的输出将如下所示:
另外,请注意 Sport
字符串对于 Lisa Townsend
是空的,因为用于实例化该实例的构造函数没有设置 Type
属性。
让我们来解决这一切。现在是您在 C# 职业生涯中学习良好习惯和做法的时候了。
abstract class Sport
运动?不,这个 class 不代表 运动 。这个 class 代表 玩家 。运动就是他们玩的。您在 Main
中将本地命名为 "athlete" 的事实告诉您您在这里犯了一个错误。称其为 Athlete
或 Player
或其他名称。假设 Player
,因为这样派生的 classes 可以是 TennisPlayer
和 GolfPlayer
或 Golfer
.
protected string name;
protected int age;
为什么要保护?你有 public getters 和 setters 包装这些!
完全消除支持字段。
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
这些都是不必要的罗嗦;使用自动属性。
public int Age
时代在不断变化;生日没有。存储生日,然后查看
How to calculate an age based on a birthday?
public abstract void Performance();
我不知道这是什么意思,但它可能是错误的。抽象方法通常是动词,但这是一个名词。这不应该是Perform
吗?或 Play
?您从派生的 classes 中省略了它,所以让我们忽略它。
我们还想说说我们玩什么运动。因此,让我们为此创建一个类型。放在一起:
enum Sport { Tennis, Golf }
public abstract class Player
{
// Consider making Name and Birthday get-only as well.
// Is there any situation in which they change after construction?
// If not, then *don't allow them to change*!
public string Name { get; set; }
public DateTime Birthday { get; set; }
public abstract Sport Sport { get; }
public Player(string name, DateTime birthday)
{
this.Name = name;
this.Birthday = birthday;
}
}
更短更容易理解。现在让我们推导出一些类型。我们将再次缩短属性,并添加一个 ToString。
另外,Rating
真的是double吗?对身高或体重等物理量使用双打。我怀疑这是 decimal,而不是 double。如果将 3.4 的评级实际存储为 3.39999999999999999 是绝对错误的,那么双精度是错误的类型,小数是正确的类型。
public sealed class TennisPlayer : Player
{
public override Sport Sport => Sport.Tennis;
// Again, do these change after construction? If not
// then remove the setters.
public decimal Rating { get; set; }
public int ServeSpeed { get; set; }
public TennisPlayer(string name, DateTime birthday, decimal rating, int speed) : base(name, birthday)
{
this.Rating = rating;
this.ServeSpeed = speed;
}
public override string ToString()
{
return @"Tennis player: {Name} {Birthday} {Rating} {ServeSpeed}";
}
}
同样,更短更易于阅读。现在你对 GolfPlayer
或 Golfer
或任何你称之为的东西做同样的事情。