【问题标题】:Abstract parameters and methods beginner抽象参数和方法初学者
【发布时间】:2021-07-05 02:34:30
【问题描述】:

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

现在的结果是,两个派生类的 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);
    }
}

【问题讨论】:

  • Bpm 不是抽象属性(它没有被声明为abstract);它是抽象类中的常规属性。
  • protected int bpm;public int Bpm { get; set; } 无关,只是名称相似。
  • @Llama 哦!好的我明白了。那么我猜我在派生类中引用属性的方式也必须改变?

标签: c# inheritance abstraction


【解决方案1】:

原答案

首先,这个:

    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# 是区分大小写的。


扩展答案

那么我如何让“Bpm”和“bpm”匹配,比如“Genre”和“genre”匹配?

您已经实现了带有支持字段genreGenre 属性:

    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
    }

我想通过虚方法运行一个抽象属性,并最终将结果分配给该属性

如果我理解正确,您希望 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)。不要让语法迷惑你。

【讨论】:

  • 感谢您的帮助!那么我如何让Bpmbpm 匹配,比如Genregenre 匹配?或者它对常规属性和抽象属性的工作方式不同?
  • @Mike 查看扩展答案。
  • 哇,谢谢你!我昨天一整天都在复习课堂笔记,试图弄清楚这一点:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-22
  • 1970-01-01
  • 1970-01-01
  • 2011-03-10
  • 2017-10-28
相关资源
最近更新 更多