Операторы объединения с нулем с операндами разных типов

Вопрос или проблема

Операторы объединения с нулем с операндами разных типов

Я понимаю, что вы не можете объединить разные типы в один результат, но не понимаю, почему это так.

Например:

Guid? ID;
int ID2;
var ID3 = ID ?? ID2;

Этот код не работает, независимо от того, является ли ID нулевым или каков тип ID3: var, object и т.д.

Может кто-то объяснить, почему это не разрешено?

Мой реальный код выглядит так:

public StandAloneMachine Get(int id, Guid? FKGuid = null, string FKName = "") 
{ 
    var parameters = new Parameters() 
    { 
        new Parameter("id", FKGuid ?? id) 
    }; 
}

У кого-нибудь есть причина, почему это не разрешено?

Таково устройство языка. Что он должен делать? Как преобразовать int, который является 32-битным числом, в GUID, который является структурой, состоящей из нескольких частей числа, или наоборот?

Этот код:

var ID3 = ID ?? ID2

в преобразованных типах означает (псевдокод):

(выясненный тип) = Guid? ?? int;

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

В любом случае, оператор объединения нулей возвращает одно значение, и оба его аргумента слева и справа должны быть оценены в значение одного типа. Следовательно, результат может быть либо Guid, либо int. (выясненный тип) будет тогда этим типом. Тем не менее, ?? не может преобразовать значения операндов Guid и int в значение такого единого типа.

Примечание: Можно утверждать, что компилятор может выбрать object как ближайший совместимый тип как с Guid, так и с int, и просто упаковать эти значения в объект. Однако это подорвет сам смысл строгой проверки типов. Это будет просто ‘слишком расслаблено’.

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

var parameters = new Parameters() 
{ 
    new Parameter("id", FKGuid.HasValue ? ToTypeParameterExpects(FKGuid.Value) : ToTypeParameterExpects(id)) 
}; 

Очевидно, что ToTypeParameterExpects – это преобразование в любой тип, который ожидает конструктор Parameter для значения.

Ответ или решение

Использование оператора объединения с нулевым значением (null-coalescing operator) в C# требует, чтобы операнды имели совместимые типы. Ваша проблема связана с тем, что вы пытаетесь объединить значения разных типов: Guid? и int.

Давайте разберем это подробнее.

Причина ограничений

Оператор ?? предназначен для возврата первого не-null значения из двух возможных значений. Это означает, что компилятор должен определить единый тип для результата, который может быть возвращен. В вашем примере:

Guid? ID;
int ID2;
var ID3 = ID ?? ID2;

Компилятор пытается вывести тип для ID3. Первый операнд (ID) является Guid?, а второй (ID2) — int. Эти два типа несовместимы. Guid — это структура, состоящая из нескольких частей, а int — это 32-битное целое число.

Совместимость типов

В C# важна строгая типизация, которая требует, чтобы типы в выражениях были совместимыми. Оператор ?? не может автоматически преобразовать один тип в другой (например, Guid в int или наоборот), поскольку это может привести к несоответствиям в значениях, которые они представляют. Компилятор не может «угадывать», какой тип использовать, и не может просто взять object как общий тип, так как это ослабит строгую типизацию.

Решение проблемы

В вашем конкретном случае, чтобы обойти эту проблему, воспользуйтесь тернарным оператором ?:, чтобы явно указать, какой тип вы хотите использовать в зависимости от наличия значения:

public StandAloneMachine Get(int id, Guid? FKGuid = null, string FKName = "") 
{ 
    var parameters = new Parameters() 
    { 
        new Parameter("id", FKGuid.HasValue ? ToTypeParameterExpects(FKGuid.Value) : ToTypeParameterExpects(id)) 
    }; 
}

Здесь ToTypeParameterExpects — это функция (или метод), которая преобразует значение нужного типа в ожидаемый тип параметра. Таким образом, вы явно указываете к какому типу вы хотите привести значения в зависимости от их наличия, что делает ваш код более читаемым и понятным, а также соблюдает правила типизации C#.

Заключение

Хотя использование оператора ?? в данном случае было бы удобно, для работы с несовместимыми типами, такими как Guid? и int, лучше использовать тернарный оператор и ручные преобразования типов. Это гарантирует, что ваш код будет компилироваться и гарантирует соблюдение строгой типизации, которая является одним из основных принципов C#.

Оцените материал
Добавить комментарий

Капча загружается...