Я просто практикуюсь в своем курсе кодирования. Я только начал с абстракции, так что для меня это все еще немного сбивает с толку. У меня есть этот код, и пока мне удалось присвоить значения обычным свойствам. Я хочу запустить абстрактное свойство с помощью виртуального метода и, наконец, присвоить свойству результат. Абстрактный метод следует переопределить во втором производном классе, но не в первом.
На данный момент результат таков, что свойство 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);
}
}
И protected int bpm; не имеет отношения к public int Bpm { get; set; }, за исключением того, что имеет схожие имена.
@Llama Ой! Хорошо, я вижу. Итак, я предполагаю, что способ ссылки на свойство в производных классах также должен измениться?





Прежде всего, это:
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 видит расширенный ответ.
вау спасибо за это! Я вчера весь день просматривал конспекты занятий, пытаясь понять это :)
Bpmне является абстрактным свойством (он не объявлен какabstract); это обычное свойство абстрактного класса.