Абстрактные параметры и методы новичок

Я просто практикуюсь в своем курсе кодирования. Я только начал с абстракции, так что для меня это все еще немного сбивает с толку. У меня есть этот код, и пока мне удалось присвоить значения обычным свойствам. Я хочу запустить абстрактное свойство с помощью виртуального метода и, наконец, присвоить свойству результат. Абстрактный метод следует переопределить во втором производном классе, но не в первом.

На данный момент результат таков, что свойство 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); это обычное свойство абстрактного класса.
Llama 09.04.2021 11:08

И protected int bpm; не имеет отношения к public int Bpm { get; set; }, за исключением того, что имеет схожие имена.

Llama 09.04.2021 11:09

@Llama Ой! Хорошо, я вижу. Итак, я предполагаю, что способ ссылки на свойство в производных классах также должен измениться?

Mike 09.04.2021 11:10
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
43
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Оригинальный ответ

Прежде всего, это:

    public int Bpm //abstract property
    {
        get;
        set;
    }

Это не абстрактное свойство. Здесь вы видите Автоматически реализованная собственность. Это свойство, для которого компилятор создает скрытое резервное поле.


Во-вторых, здесь:

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

Но это поле не имеет ничего общего с вышеупомянутым свойством.


Повторюсь, bpm и Bpm не связаны. Полагаю, я должен также упомянуть, что 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.


Я брошу вам кривую голову и скажу, что вы можете реализовать Genre так, как вы реализовали Bpm, и это будет работать. Вот что бы вы сделали:

  • Удалите защитное поле 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);
        }
    }

Это просто сокращение писать меньше кода… Что кусает меня в спину, потому что я должен это объяснить.. См. Члены с телом выражений (руководство по программированию на C#). Пусть вас не смущает синтаксис.

Спасибо, что помогло! Итак, как мне сделать так, чтобы Bpm и bpm совпадали, как Genre и genre? Или это работает по-другому с обычными свойствами и абстрактными свойствами?

Mike 09.04.2021 11:17

@Mike видит расширенный ответ.

Theraot 09.04.2021 11:33

вау спасибо за это! Я вчера весь день просматривал конспекты занятий, пытаясь понять это :)

Mike 09.04.2021 11:57

Другие вопросы по теме