C# 抽象参数和方法初学者
我只是在为我的编码课程做一些练习。我刚刚开始抽象,所以对我来说还是有点合拍。我已经得到了这段代码,到目前为止,我已经成功地为常规属性赋值。我想通过虚拟方法运行一个抽象属性,并最终将结果分配给该属性。抽象方法应该在第二个派生类而不是第一个派生类上重写 现在的结果是,两个派生类的BPM属性的值都是0,尽管我不知道为什么C# 抽象参数和方法初学者,c#,inheritance,abstraction,C#,Inheritance,Abstraction,我只是在为我的编码课程做一些练习。我刚刚开始抽象,所以对我来说还是有点合拍。我已经得到了这段代码,到目前为止,我已经成功地为常规属性赋值。我想通过虚拟方法运行一个抽象属性,并最终将结果分配给该属性。抽象方法应该在第二个派生类而不是第一个派生类上重写 现在的结果是,两个派生类的BPM属性的值都是0,尽管我不知道为什么 public abstract class Music { protected string genre; protected int bpm; publi
public abstract class Music
{
protected string genre;
protected int bpm;
public string Genre //property
{
get
{
return genre;
}
set
{
genre = value;
}
}
public int Bpm //abstract property
{
get;
set;
}
public virtual int BPM(int b) //virtual method
{
this.bpm = b;
return b;
}
public Music(string genre, int bpm)
{
this.genre = genre;
this.bpm = BPM(bpm);
}
}
public class Techno : Music
{
public Techno(string genre, int bpm) : base(genre, bpm) { }
}
public class Dubstep : Music
{
public override int BPM(int b)
{
return base.BPM(b) / 2;
}
public Dubstep(string genre, int bpm) : base(genre,bpm) { }
}
//PROGRAM-------------------------------------------------------------
class Program
{
static void Main()
{
Techno t = new Techno("Techno", 130);
Dubstep d = new Dubstep("Dubstep", 140);
Console.WriteLine(t.Genre + " " + d.Genre);
Console.WriteLine(t.Bpm + " " + d.Bpm);
}
}
原始答案 首先,这是:
public int Bpm //abstract property
{
get;
set;
}
不是抽象属性。你现在看到的是一个。这是编译器为其创建隐藏备份字段的属性
第二,这里:
Console.WriteLine(t.Bpm + " " + d.Bpm);
您使用的是上述财产……而不是其他任何地方。它从未被赋值,因此它有其默认值,即0
你看,你有一个字段
protectedintbpm在方法中使用的代码>:
public virtual int BPM(int b) //virtual method
{
this.bpm = b;
return b;
}
您还可以在构造函数中设置它:
public Music(string genre, int bpm)
{
this.genre = genre;
this.bpm = BPM(bpm);
}
但该字段与上述属性无关
重申bpm
和bpm
是不相关的。我想我还应该提到C#是区分大小写的
扩展答案
那么,我如何让“Bpm”和“Bpm”匹配,比如“流派”和“流派”匹配
您已经使用一个支持字段流派
实现了流派
属性:
public string Genre //property
{
get
{
return genre;
}
set
{
genre = value;
}
}
这类似于编译器对Bpm
所做的操作。唯一的区别是您无法访问Bpm
备份字段
我会给你一个曲线球,告诉你你可以用你实现Bpm
的方式来实现Genre
,它会工作的。这就是你要做的:
- 删除支持字段
类型
- 使
流派
自动实现:公共字符串流派{get;set;}
- 让构造函数设置属性
Genre=Genre代码>
因此,您将看到您的代码更简单、更短。这就是自动实现属性的要点
因此,不,作为一个自动实现的属性并不会阻止Bpm
工作。问题是您使用的字段bpm
与此无关
您可以从构造函数写入属性,而不是写入无关字段,例如:
public Music(string genre, int bpm)
{
Genre = genre; // Set Genre property
Bpm = bpm; // Set Bpm property
}
我想通过虚拟方法运行一个抽象属性,并最终将结果分配给该属性
如果我理解正确,您希望Dubstep d=newdubstep(“Dubstep”,140)
将具有值为80
的Bpm
。对吧?
因此,我们希望所有写入都通过该方法。这就是你如何做到的:
public abstract class Music
{
private int bpm;
public Music(string genre, int bpm)
{
Genre = genre;
Bpm = bpm;
}
public int Bpm
{
get => bpm;
set => bpm = BPM(value);
}
public string Genre { get; set; }
public virtual int BPM(int b) //virtual method
{
return b;
}
}
在这里,Bpm
不再自动实现。它将读取和写入字段pbm
此外,体裁是自动实现的。我这样做是因为我们不需要对它做任何特殊的事情
现在,每次设置属性时,都将运行bpm=bpm(value)
。它将调用虚拟方法,该方法将重写Dubstep,从而产生所需的行为
明确地说,该代码:
public int Bpm
{
get => bpm;
set => bpm = BPM(value);
}
public int Bpm
{
get
{
return bpm;
}
set
{
bpm = BPM(value);
}
}
与此代码相同:
public int Bpm
{
get => bpm;
set => bpm = BPM(value);
}
public int Bpm
{
get
{
return bpm;
}
set
{
bpm = BPM(value);
}
}
写更少的代码只是一种简捷的方法……这让我很头疼,因为我得解释一下。看见不要让语法迷惑你。Bpm
不是一个抽象属性(它不是声明的abstract
);它是抽象类中的常规属性除了有相似的名字外,code>与public int Bpm{get;set;}
无关。@Llama噢!好的,我明白了。那么我想我在派生类中引用属性的方式也必须改变吗?谢谢你的帮助!那么我如何使Bpm
和Bpm
匹配,比如Genre
和Genre
匹配?或者它对常规属性和抽象属性有不同的作用吗?@Mike see extended answer.wow谢谢你!我昨天一整天都在复习课堂笔记,想弄明白这一点:)