Я пытаюсь понять концепцию наследования классов в PowerShell. У меня почти все работает, просто нужно, чтобы кто-нибудь объяснил ошибку и пустой конструктор, который я случайно обнаружил.
Я определяю базовый класс.
class Human {
[string]$name
[string]$gender
Human(){} # Comment out this line and hit error
Human($name, $gender)
{
$this.name = $name
$this.gender = $gender
}
[void]Speak()
{
Write-Host -ForegroundColor Green "I am a human"
}
}
Определите класс Teacher, производный от класса Human.
class Teacher : Human {
# Don't need to repeat $name & $gender if inherit from Human class
# Introduce new class property -> $subject
[string]$subject
Teacher($name, $gender, $subject)
{
$this.name = $name
$this.gender = $gender
$this.subject = $subject
}
# Overrides Speak() method in Human class
[void]Speak()
{
Write-Host -ForegroundColor Green "I am a $($this.subject) teacher"
}
}
$t1 = [Teacher]::new("Steven", 'Male', 'English')
$t1
$t1.Speak()
Экземпляр $t1 отлично работает со следующим выводом.
subject name gender
------- ---- ------
English Steven Male
I am a English teacher
Я получу следующий вывод с сообщением об ошибке, если закомментируете Human(){} в классе Human. Хотя PowerShell по-прежнему выводит выходные данные для $t1 и $t1.Speak(). Для справки: я использую PowerShell 7.4.2 в VS Code. И вот моя ссылка на наследование классов.
MethodException:
Line |
8 | {
| ~
| Cannot find an overload for "new" and the argument count: "0".





По сути:
Добавляя перегруженный конструктор в базовый класс, производный класс пытается наследовать и перегрузить конструктор по умолчанию базового класса.
Но нет конструктора по умолчанию, который можно было бы наследовать.
Таким образом ошибка.
tl;dr: всегда пишите конструктор по умолчанию.
Ошибка, которую вы видите при удалении пустого конструктора, связана с тем, что вам не хватает аргументов, передаваемых конструктору базового класса, $name и $gender в данном случае:
class Teacher : Human {
[string] $subject
Teacher($name, $gender, $subject) : base($name, $gender) {
# assignments of `.name` and `.gender` can be omitted here
# as the base `.ctor` is already taken care of those
$this.subject = $subject
}
[void] Speak() {
Write-Host -ForegroundColor Green "I am a $($this.subject) teacher"
}
}
Наследование хорошо описано в about_Classes_Inheritance однако ключевое слово base не уделяет особого внимания и, насколько мне известно, не существует документации PowerShell, посвященной конкретно этому ключевому слову. Однако для C# есть один: base (Справочник по C#).
Конечно, между обоими языками есть некоторые различия, например, примеры взяты из связанного документа:
public DerivedClass(int i) : base(i)
Очень похоже можно перевести:
DerivedClass([int] $i) : base($i)
Однако при вызове метода базового класса:
public override void GetInfo()
{
// Calling the base class GetInfo method:
base.GetInfo();
// ...
}
Специальной переменной $base для ссылки на базовый класс не существует. В PowerShell приведенный выше перевод будет выглядеть следующим образом:
[void] GetInfo() {
# Calling the base class GetInfo method:
([Person] $this).GetInfo();
# ...
}
это точно, и это моя вина, потому что я тоже это пропустил! хороший улов @OngK.S !
TQ @'Сантьяго Скуарзан'. Теперь это работает. Я только заметил, что могу опустить
$this.nameи$this.gender, поскольку они унаследованы от класса Human. Верна ли эта идея?