抽象参数和方法初学者

Abstract parameters and methods beginner

我只是在为我的编码课程做一些练习。我刚刚开始抽象,所以它对我来说仍然有点混乱。我有这段代码,到目前为止我已经设法为常规属性赋值。我想通过虚拟方法 运行 抽象 属性 并将结果分配给 属性 最后。抽象方法应该在第二个派生 class 而不是第一个

上被覆盖

现在的结果是两个派生的 classes 的 BPM 属性 的值为 0,但我不确定为什么。

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;
    }

不是摘要属性。您在这里看到的是 Auto-implemented property。这是一个 属性,编译器为其创建了一个隐藏的支持字段。


二、这里:

Console.WriteLine(t.Bpm + " " + d.Bpm);

你用上面提到的属性…其他地方都没有。它从来没有被赋值,所以它有它的默认值,恰好是0。


你看,你有一个字段 protected int bpm; 在你的方法中使用:

    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);
    }

但是那个字段和前面提到的属性没有任何关系。


重申 bpmBpm 是无关的。 我想我还应该提到 C# 区分大小写。


扩展答案

So how would I make 'Bpm' and 'bpm' match, like 'Genre' and 'genre' match?

您已经实现了 Genre 属性 和支持字段 genre:

    public string Genre //property
    {
        get
        {
            return genre;
        }
        set
        {
            genre = value;
        }
    }

这类似于编译器为 Bpm 所做的事情。唯一的区别是您无法访问 Bpm 支持字段。


我会抛给你一个曲线球,并说你可以按照你实现 Bpm 的方式实现 Genre,它会起作用。这就是你要做的:

  • 删除支持字段genre
  • 使 Genre 自动执行:public string Genre { get; set; }
  • 让构造函数设置 属性 Genre = genre;.

结果,您会发现您的代码更简单、更短。这就是自动实现属性的意义所在。

所以,不,作为一个自动实现的 属性 并不会阻止 Bpm 工作。问题是您使用的字段 bpm 与它无关。

您可以从构造函数写入 属性,而不是写入不相关的字段,例如:

    public Music(string genre, int bpm)
    {
        Genre = genre; // Set Genre property
        Bpm = bpm; // Set Bpm property
    }

I want to run an abstract property through a virtual method and have the result assigned to the property finally

如果我没理解错的话,你希望 Dubstep d = new Dubstep("Dubstep", 140);Bpm,值为 80。对吗?

所以,我们希望所有的写入都通过该方法。这就是你的做法:

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);
        }
    }

这只是一种简写,可以少写代码……这让我很反感,因为我得解释一下。参见 Expression-bodied members (C# programming guide)。不要让语法混淆你。