Передача сущности производного класса универсальным методам

У меня четыре класса:

class BaseA { }

public class DerivedA : BaseA { }

public class BaseB
{
    public BaseA SomeProperty { get; set; }
}

public class DerivedB : BaseB
{
    public new DerivedA SomeProperty { get; set; }
}

которые используются в программе, например:

static void Main(string[] args)
{
    var derivedB = new DerivedB();
    derivedB.SomeProperty = new DerivedA();

    SomeMethod(derivedB);
}

static void SomeMethod<T>(T param) where T : BaseB
{
    var tmp1 = param.SomeProperty;               // null
    var tmp2 = (param as DerivedB).SomeProperty; // required value
    var tmp3 = (param as T).SomeProperty;        // null
}

Если я передаю в SomeMethod параметр типа DerivedB, param будет иметь 2 свойства SomeProperty - типов базового и производного классов. Но независимо от типа param, он рассматривается как класс BaseB, и я должен явно привести его к требуемому типу, чтобы получить правильное значение SomeProperty. Приведение к T не помогает. Должен ли я привести переменную param к ее собственному типу или я могу получить хотя бы свойство с ненулевым значением?

Все эти проблемы возникают из-за того, что вы скрываете свойство baseB в производномB. Почему бы также не сделать свойство baseB универсальным?

Zohar Peled 06.06.2018 10:41

Возможный дубликат ключевое слово "новое" в объявлении свойства в C#

CodeNotFound 06.06.2018 10:41
Стоит ли изучать 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
2
72
3

Ответы 3

But no matter of what type is param, it is treated as BaseB class and I have to explicitly cast it to required type to get the right SomeProperty value.

Да. Поскольку эта привязка выполняется во время компиляции, в этот момент компилятор знает только о BaseB.SomeProperty. Это свойство, на которое будет ссылаться IL, и свойство, которое будет извлечено во время выполнения.

Я бы сказал, что наличие двух свойств независимый с одинаковым именем действительно сбивает с толку. Если вы В самом деле хотите сделать это, вы можете принудительно выполнить привязку во время выполнения вместо использования динамической типизации:

static void SomeMethod<T>(T param) where T : BaseB
{
    dynamic d = param;
    // This will use the execution-time type of param
    var tmp1 = d.SomeProperty;
}

Но я бы полностью отказался от этого дизайна, если вы можете. Либо имеют отдельно названные свойства, поэтому они явно независимы, либо свойство с частью состояния Один, к которому можно получить доступ по-разному в зависимости от «представления» экземпляра (с риском исключений, если вы установите для свойства значение «неправильное» " тип).

Что вам нужно, так это преобразовать ваш общий к типу class вместо BaseB а типы параметров - в динамические. Это будет обрабатывать время выполнения ссылок.

static void SomeMethod<T>(T param) where T : class
        {
            dynamic tmp1 = param; 
            var myProperty = tmp1.SomeProperty;
        }

Кроме того, я не думаю, что здесь действительно нужна слежка.

Кроме того, вы можете удалить тип для общего. Он по-прежнему будет работать в вашем случае

Просто

static void SomeMethod<T>(T param)

Затенение базового свойства, вероятно, не лучший способ.

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

На ум приходят два более простых и понятных способа:

  • подумайте о создании интерфейса, который будет реализовывать базовый класс, производный класс и общий тип (используемый в SomeMethod) ... и тогда это довольно просто

  • если общий интерфейс не подходит для ваших нужд, рассмотрите возможность создания базового класса как универсального класса.

Надеюсь это поможет

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