Как определить аксессоры для детей?

У меня 3 класса:

public interface IParent
{
    String World { get; }
}

public class Parent : IParent
{
    public String World;
    {
        get
        {
            return "Hello " + this.World;
        }
    }
}

public class Children : Parent
{
    public String World = "World";
}

Как мне сделать так, чтобы средство доступа get Parent вызывалось с атрибутом WorldChildren?

this.World вызовет свойство рекурсивно!
Olivier Jacot-Descombes 07.11.2018 17:12

Что вы хотите вернуть, если я сделаю new Parent().World?

Chris 07.11.2018 17:13

Количество решений ниже. Эта проблема достаточно неоднозначна, и есть много разных подходов к ней. Если что-либо из приведенного ниже не соответствует вашим потребностям, добавьте дополнительные сведения.

Ryan Pierce Williams 07.11.2018 17:49
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
95
4

Ответы 4

Это задом наперед.

Это зависит от наследующего класса, чтобы включить поведение базового класса из переопределений если необходимо. Подкласс override поддерживает базовое поведение, но имеет привязку к базовому классу с помощью ключевого слова base.

Как таковой:

public interface IParent
{
    String World { get; }
}

public class Parent : IParent
{
    public virtual String World
    {
        get
        {
            return "Hello";
        }
    }
}

public class Children : Parent
{
    public override String World
    {
        get
        {
            return base.World + " World!";
        }
    }
}

Вы забыли отредактировать то, что намеревались сделать? Ваш Parent.World в настоящий момент кажется рекурсивным.

Chris 07.11.2018 17:23

@Chris Да, действительно. Опечатка стоила мне голоса против. Исправлено сейчас. :( Спасибо

spender 07.11.2018 17:29

Это был не я, поэтому я не могу перевернуть этот отрицательный голос. Теперь вы можете получить мой голос, если это вас утешит. :)

Chris 07.11.2018 17:33

Да, ненавижу, как быстро люди голосуют за опечатки - меня тоже ударили: /

Ryan Pierce Williams 07.11.2018 17:46

Свойство уже является частью родительского. Однако вам понадобится функция защищенного набора ... Задайте ее в конструкторе следующим образом:

public interface IParent
{
    String World { get; }
}

public class Parent : IParent
{
    public String World { get; protected set; }
    public Parent() { World = "Hello World"; }
}

public class Children : Parent
{
    public Children() { World = "World"; }
}

Однако, возможно, вы ищете что-то более похожее на это:

public interface IParent
{
    String World { get; }
}

public class Parent : IParent
{
    public String World { get; private set; }
    public Parent(String thing) { World = "Hello " + thing; }
}

public class Children : Parent
{
    public Children() : base("World") { }
}

Оба они приводят к ошибкам времени компиляции: «Parent не реализует интерфейс IParent» ... то же самое для Children. Вы также не можете установить модификаторы доступности в интерфейсе.

Ron Beyer 07.11.2018 17:18

@RonBeyer - да, была пара опечаток. Фиксированный.

Ryan Pierce Williams 07.11.2018 17:25

Я не думаю, что это то, что хочет OP, вы устанавливаете его один раз при создании объекта, но OP использует свойства и хочет то, что в настоящее время установлено дочерним элементом. В вашем случае нет дочернего свойства, которое может быть использовано родителем для получения значения для объединения с родительским свойством. На самом деле это проблема XY со стороны OP, но я не думаю, что это решает то, что OP ищет.

Ron Beyer 07.11.2018 17:28

Что касается способов решения проблемы, смоделированной в OP, как написано выше, то они верны. Может случиться так, что OP действительно следует за суффиксным подходом, опубликованным выше другими, и в этом случае этот подход должен быть отмечен как ответ. Однако, если OP не предоставляет более подробную информацию, это правильные решения проблемы, как описано.

Ryan Pierce Williams 07.11.2018 17:33

Вы можете использовать дополнительное частное поле, которое будет виртуальным, чтобы вы могли переопределить его в дочернем элементе.

Попробуй это:

public interface IParent
{
    string HelloWorld { get; }
}

public class Parent : IParent
{
    protected virtual string World { get; }

    public string HelloWorld
    {
        get
        {
            return "Hello " + World;
        }
    }
}

public class Children : Parent
{
    protected override string World { get; } = "World";
}

Или вы также можете передать строку через конструктор, а затем установить значение во время выполнения.

public interface IParent
{
    string HelloWorld { get; }
}

public class Parent : IParent
{
    private readonly string world;

    public Parent(string world)
    {
        this.world = world;
    }

    public string HelloWorld
    {
        get
        {
            return "Hello " + world;
        }
    }
}

public class Children : Parent
{
    public Children(string world) : base(world)
    {
    }
}

Используйте это так:

var children = new Children("World");
Console.WriteLine(children.HelloWorld);

Вы можете использовать второе свойство для суффикса и сделать его виртуальным, чтобы потомки могли его перезаписать.

public class Parent : IParent
{
    protected virtual string Suffix => "World";

    public String World => "Hello " + Suffix;
}

public class Children : Parent
{
    protected override string Suffix => "Again";
}

Родители отобразят «Hello World», Дети отобразят «Hello Again». Это верно только для типа времени выполнения. Статический (т.е. время компиляции) тип не имеет значения.

Parent p = new Children();
Console.WriteLine(p.World); // Displays "Hello Again"!

Здесь статический тип p - это Parent. Тип времени выполнения - Children. Такое поведение называется Полиморфизм (Руководство по программированию на C#).

Настоящий Parent не может узнать о суффиксе «Снова».

Здесь нет необходимости переопределять; если вы намерены разрешить изменение значения, просто используйте свойство с (защищенным?) установщиком.

Ryan Pierce Williams 07.11.2018 17:29

Неясно, что должен делать код, поскольку пример OP не компилируется и не запускается без исключения. Но если вы хотите сохранить часть «Hello» постоянной и переопределить только следующую часть в Children, то вы должны переопределить.

Olivier Jacot-Descombes 07.11.2018 17:34

@RyanPierceWilliams: Хотя вы могли бы сделать это с помощью защищенного установщика, тогда вам действительно нужно будет добавить код в конструктор для его установки, и это также позволит другим вещам изменить его, что может быть нежелательно. Это кажется более близким к кажущемуся намерению OP, чем ваша версия.

Chris 07.11.2018 17:35

@ OlivierJacot-Descombes в этом случае вам не нужно переопределять, потому что это решение добавляет второе свойство. Первое свойство можно оставить только для чтения, в то время как второе может поддерживать защищенный установщик (или, альтернативно, передавать значение через конструктор).

Ryan Pierce Williams 07.11.2018 17:39

@Chris намерение не было разъяснено OP в достаточной степени IMO. Если намерение состоит в том, чтобы эти вещи никогда не могли изменяться (за исключением производных), тогда подойдет переопределенное свойство, доступное только для чтения. Если цель состоит в том, чтобы производный класс мог передавать эти значения свойств обратно базовому классу, достаточно простого установщика.

Ryan Pierce Williams 07.11.2018 17:42

Если целью было просто отобразить разные значения, переданные через конструктор, вы могли бы сделать это только с классом Parent. Нет необходимости в классе Children.

Olivier Jacot-Descombes 07.11.2018 17:45

@ OlivierJacot-Descombes В самом деле. Или у вас может быть защищенный конструктор, который могут вызывать только производные классы, если намерение состоит в том, чтобы разрешить только производным классам изменять его. Несколько способов решения проблемы, в общих чертах описанных в OP.

Ryan Pierce Williams 07.11.2018 17:47

да. Плохо сформулированные вопросы приводят к длинным спискам комментариев.

Olivier Jacot-Descombes 07.11.2018 17:53

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