Данный:
//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 не сможет принимать нулевые значения. Но в данном случае мы доступны только для чтения, так что это «может» работать.
Если у кого-то есть хороший способ решить эту проблему, пожалуйста, дайте мне знать.
Пожалуйста, публикуйте реальный код, когда задаете вопрос.





Вы можете добавить атрибут NotNull к свойству ObjectB Id.
class ObjectB : IMaybeHasId
{
[NotNull]
public int? Id => 10;
}
По крайней мере, теперь в IDE это значение никогда не будет null. Если вы проверите это свойство на нулевое значение в своем коде, вы получите подсказку типа, сообщающую, что проверка избыточна, потому что она никогда не будет null.
Однако вы не можете изменить фактический тип свойства. Как насчет добавления нового свойства в ObjectB, public int RequiredId { get; }, которое скрыто использует свойство IMaybeHasId.Id?
Вы проверяли это перед публикацией?
Вам необходимо явно реализовать интерфейс. Тогда вы сможете легко сохранить 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.
Похоже, вам нужен
IHasId, аClass ObjectAэтого не реализует. Тогда проверить это вы можете(someObj as IHasId)?.Id