C# Как преодолеть обнуляемость интерфейса для геттеров

Данный:

//Common interface for objects that may have an Id value
interface IMaybeHasId
{
    int? Id { get; }  //Note this is a GET only
}

//Object A never has an Id, this code works fine
class ObjectA : IMaybeHasId
{
    public int? Id => null;
}

//Object B always has an Id
//This code will not work as Id here is Int not Int?
class ObjectB : IMaybeHasId
{
    public int Id => 10;
}

Мне это нужно, потому что, когда мой код работает с чистой ссылкой на объект B, код может ожидать, что идентификатор всегда доступен.

При работе с чистой ссылкой на объект A идентификатор может быть недоступен.

Но я хочу поместить их в общую коллекцию, т.е. List().

При работе с элементами в списке можно беспокоиться о том, что идентификатор может быть нулевым в соответствии с интерфейсом. Т.е. у нас будет ссылка на объект через контракт интерфейса, где Id — Int? Абсолютно нормально.

Компилятор остановит компиляцию приведенного выше кода.

Это настоящая боль, поскольку с человеческой точки зрения здесь нет реальной проблемы. Контракт объекта B (всегда имеющий идентификатор) будет соответствовать интерфейсу, согласно которому тип объекта может иметь идентификатор. Обратите внимание, что этот контракт является GET, поэтому наличие ненулевого значения соответствует ограничению, допускающему значение NULL. Просто оно никогда не бывает нулевым.

Очевидно, это не сработало бы, если бы свойство было доступно для записи/установки. Потому что объект B не сможет принимать нулевые значения. Но в данном случае мы доступны только для чтения, так что это «может» работать.

Если у кого-то есть хороший способ решить эту проблему, пожалуйста, дайте мне знать.

Похоже, вам нужен IHasId, а Class ObjectA этого не реализует. Тогда проверить это вы можете (someObj as IHasId)?.Id

Charlieface 02.05.2024 03:00

Пожалуйста, публикуйте реальный код, когда задаете вопрос.

Enigmativity 02.05.2024 03:30
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
2
98
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вы можете добавить атрибут NotNull к свойству ObjectB Id.

class ObjectB : IMaybeHasId
{
    [NotNull]
    public int? Id => 10;
}

По крайней мере, теперь в IDE это значение никогда не будет null. Если вы проверите это свойство на нулевое значение в своем коде, вы получите подсказку типа, сообщающую, что проверка избыточна, потому что она никогда не будет null.

Однако вы не можете изменить фактический тип свойства. Как насчет добавления нового свойства в ObjectB, public int RequiredId { get; }, которое скрыто использует свойство IMaybeHasId.Id?

Вы проверяли это перед публикацией?

Enigmativity 02.05.2024 04:54
Ответ принят как подходящий

Вам необходимо явно реализовать интерфейс. Тогда вы сможете легко сохранить public int Id => 10;, но при этом реализовать интерфейс.

class ObjectB : IMaybeHasId
{
    public int Id => 10;
    int? IMaybeHasId.Id => this.Id;
}

Продолжая отличный ответ @Enigmativity, я предлагаю:

interface IMaybeHasId
{
    int? Id { get; }
}

interface IHasId
{
    int Id { get; } 
}

class ObjectB : IMaybeHasId, IHasId
{
    public int Id => 10; // this will implement IHasId
    int? IMaybeHasId.Id => this.Id; // this will implement IMaybeHasId
}

Таким образом, если у вас есть ObjectC, похожий на ObjectB, сходство (что вы хотите облегчить доступ к необработанным данным int) становится очевидным через IHasId.

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

Похожие вопросы

Невозможно получить ProjectContext для Project Online из SharePoint Office 365 и получить ошибку 403 в .NET 8
Как исправить значения положения мыши, чтобы они были большими в единице
WinUI 3 Как создать библиотеку пользовательских элементов управления
Несколько экземпляров объекта, предоставляемого посредством внедрения зависимостей
Могу ли я настроить автоматическое выполнение асинхронной операции после завершения другой асинхронной операции?
Как выбрать строку сетки данных, щелкнув за пределами содержимого
Как решить исключение «Неожиданный источник запроса: присоединиться к ICacheEntry в CacheQueryable» при выполнении левого соединения с использованием linq в Apache Ignite?
Вызов универсального метода расширения с типом, известным во время выполнения, в качестве аргумента
Получение ошибки «Данные имеют значение Null» при доступе к полям базы данных на C#. Почему «?» работает, а если оператор нет
Каков синтаксис XAML для передачи нескольких значений перечисления в параметр преобразователя в MAUI?