Я использовал блокнот Polyglot Visual Studio Code и написал следующее в трех отдельных ячейках в порядке, указанном ниже.
Ячейка 1:
class Z;
Ячейка 2:
class A
{
public static void f()
{
Console.WriteLine(Z.x);
}
}
Ячейка 3:
class Z: A
{
public static int x = 42;
}
Затем я выполнил ячейки по порядку и получил следующее сообщение об ошибке.
'Z' does not contain a definition for 'x'
Мой первоначальный вопрос был:
Возможно ли на C# написать (возможно, абстрактный) класс
A, который имеет (возможно, статическую) функцию с сигнатуройvoid f(B b), типом параметра которойBявляется (возможно, абстрактный) класс, производный отA(class B: A {...})? Если нет, то почему?
и он назывался «Может ли класс C# использовать производный класс?»
Я принял ответ ниже, основанный на этой формулировке. Эта формулировка позже была удалена другим пользователем, который отредактировал мой вопрос и изменил его заголовок.
@MakePeaceGreatAgain Тот факт, что я не могу что-то сделать, не означает, что это невозможно сделать, и не объясняет, почему.
Итак, вы попробовали это? Какой код вы пробовали и какое сообщение об ошибке было?
это правда, но если вы попробовали это, скорее всего, вы уже ответили на вопрос. Что здесь определенно так.
Пожалуйста, уточните фразу «Я не могу что-то сделать». Похоже, вы что-то попробовали и получили ошибку.
Я попробовал это в блокноте Visual Studio Code Polyglot, написав классы в двух отдельных ячейках, и это не сработало. Но я думаю, если я напишу их обоих в одной ячейке, то это сработает.
и какая конкретно ошибка у тебя вылезла? «Не сработало» — это неправильное описание проблемы, оно может означать что угодно.
почему вы вообще использовали ячейку 1, если все равно определяете класс в ячейке 3? Я думаю, что когда вы удаляете ячейку1, она должна работать по назначению.
Если вы поместите все три части в одну ячейку, код будет недействителен, поскольку существует несколько объявлений класса Z. Если вы затем удалите начальный class Z;, код станет действительным и должен работать должным образом.
@MakePeaceGreatAgain Потому что я думал, что ошибка произошла из-за того, что класс A не знал о существовании класса Z.
@phuzi Да, это то, что я сделал. Я объединил ячейки 2 и 3 и выполнил эту объединенную ячейку.
@EvanAad, спасибо, что приняли мой ответ, основанный на исходном контексте вопроса. Однако в следующий раз я думаю, что вместо того, чтобы менять контекст, вам лучше просто задать новый вопрос.
@MakePeaceGreatAgain Мне показалось, что я понял исходный вопрос, который кажется довольно прямолинейным, и ответил соответственно. Я не понимаю, почему вы думаете, что я поступил несправедливо. Как я уже упоминал выше, я считаю, что контекст вопроса не следует менять, чтобы сделать недействительными существующие ответы. Пожалуйста, объясните, где я вел себя несправедливо (я согласен, что здесь важно сохранять справедливое поведение) ?
@wohlstad Я просто заметил: лично я упустил более широкую картину, поэтому проголосовал за закрытие. Если вы думаете, что вопрос был достаточно ясен, смело отвечайте – и, возможно, упустите суть. Я не хотел тебя обидеть.
@MakePeaceGreatAgain, никакого вреда не будет. Оглядываясь назад, я согласен, что более широкая картина действительно имела отношение к реальной проблеме, с которой столкнулся ФП. Но когда я прочитал это вначале, мне это показалось довольно простым.





Да, конечно. Это полностью справедливо:
class A
{
public B GetDerived() => new B();
}
class B : A
{
// ...
}
Разумеется, эти два класса должны находиться в одной сборке, поскольку им необходимо знать друг друга. Другой вопрос касается соответствующего варианта использования, который мне трудно представить. Обычно, если A является абстрактным, вы возвращаете A (которые тогда должны быть производными типами A), а не B, поскольку это не позволяет вам позже создать класс C, который является производным от A и который заменит B.
Да, это возможно.
Вот пример, который соответствует именно тому, что вы просили:
using System;
class A
{
public void f(B b)
{
Console.WriteLine("in A.f. b.Prop = " + b.Prop.ToString());
}
}
class B : A
{
public int Prop { get; set; } = 0;
}
class Program
{
static void Main(string[] args)
{
B b1 = new B();
b1.Prop = 1;
B b2 = new B();
b2.Prop = 2;
b1.f(b2);
A a = new A();
a.f(b1);
}
}
Выход:
in A.f. b.Prop=2
in A.f. b.Prop=1
Примечание:
Поскольку вы спросили, A и/или B также могут быть абстрактными.
Обновление:
Вопрос был отредактирован после того, как был дан этот ответ, с добавлением дополнительных подробностей об использовании блокнота Полиглот.
По поводу этой дополнительной информации: проблема связана с тем, как блокнот выполняет ячейки одну за другой. Это не проблема, связанная с C# в целом или с использованием наследования в частности.
Блокнот выполняет ячейки одну за другой. Итак, когда вы выполняете ячейку 2, Z — это не что иное, как class, без какого-либо понятия x. Вот почему вы получаете ошибку.
Непонятно, какое поведение вы на самом деле хотите. Конечно, вы можете просто записать весь код в одну ячейку:
class A
{
public static void f()
{
Console.WriteLine(Z.x);
}
}
class Z: A
{
public static int x = 42;
}
Так что ваша проблема связана не с наследованием, а с тем, как Полиглот выполняет ячейки. Однако имейте в виду, что ваш подход довольно странный. Базовый класс никогда не должен делать никаких предположений о производных классах, он вообще не должен знать о существовании каких-либо производных классов. Однако это скорее концептуальная проблема, которая слишком широка для этого вопроса.
Кроме того (к ОП), обычно считается странным получать доступ к членам дочернего элемента из родительского (вызов Z.<anything> изнутри A). Возможно, вам захочется действительно спросить, почему вы это делаете, и, если возможно, провести рефакторинг.
почему бы просто не попробовать это самому?