Как я могу проверить, был ли создан экземпляр структуры?

22

У меня есть структура, которая (для целей этого вопроса) в значительной степени имитирует встроенный тип Point .

Мне нужно проверить, что он был создан, прежде чем его использовать. Когда это было Point , я мог сделать это:

if (this.p == null)

Но теперь возникает следующая ошибка:

Operator '==' cannot be applied to operands of type 'ProportionPoint' and '<null>'

Как я могу сравнить мою структуру с нулем? Есть ли другой способ проверить наличие экземпляров?

    
задан Tom Wright 01.10.2012 в 14:39
источник
  • Почему вы используете struct против класса? –  Kirill Bestemyanov 01.10.2012 в 15:13

10 ответов

27

struct является типом значения - оно никогда не равно нулю.

Вы можете проверить значение default(ProportionPoint) , которое является значением структуры по умолчанию (например, ноль). Тем не менее, в некоторых случаях значение по умолчанию - источник - также является "допустимым" значением.

Вместо этого вы можете использовать Nullable<ProportionPoint> .

    
ответ дан Rawling 01.10.2012 в 14:43
  • Спасибо. Вы можете узнать о происхождении = значение по умолчанию. Возможно, он использовал nullable, но понял, что поведение, которое я хочу, соответствует классу лучше, чем структура. –  Tom Wright 01.10.2012 в 14:53
  • И это, или, в частности, его отсутствие, является причиной того, что тревожное количество объектов NHS было когда-то «расположено» к югу от Ганы и к западу от Габона. –  CJPN 17.11.2016 в 19:47
11
Структуры

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

if (this.p.Equals(default(ProportionPoint)))
    
ответ дан Darin Dimitrov 01.10.2012 в 14:42
  • Обратите внимание, что проверка по умолчанию не позволит вам различать «неинициализированное» значение и значение «правильно инициализировано по умолчанию» (например, (0, 0)) –  Jon Skeet 01.10.2012 в 14:50
  • @DarinDimitrov Не работает для меня. Оператор '==' не может применяться к операндам типа «Vhdx.RegionTableEntry» и «Vhdx.RegionTableEntry». –  Brans Ds 28.02.2014 в 14:22
  • Не работает. Должен использовать оператор Equals, а не == –  toddmo 28.01.2017 в 21:34
4

, поскольку p является struct, она никогда не будет нулевой, поэтому вы должны сравнить ее со значением по умолчанию. Для того, чтобы проверить эквивалентность между вашим значением и значением по умолчанию.  Если вы используете ==, вы получите

cannot be applied to operands of type 'ProportionPoint' and 'ProportionPoint' error

потому что структуры не получают реализацию == по умолчанию. поэтому вам нужно перегрузить операторы == и! = в вашей структуре следующим образом:

public static bool operator ==(firstOperand op1,  secondOperand2 op2) 
{
    return op1.Equals(op2);
}

public static bool operator !=(firstOperand op1,  secondOperand2 op2) 
{
   return !op1.Equals(op2);
}

а затем:

if (this.p == default(ProportionPoint))

другой вариант - использовать Equals напрямую:

f (this.p.Equals.default(ProportionPoint))
    
ответ дан Technovation 15.07.2016 в 19:50
2

Структура не может быть нулевой . Это тип значения , а не ссылочный тип. Вы должны проверить свойства со значениями по умолчанию. Что-то вроде:

if(p.X == 0 && p.Y == 0)
    
ответ дан Habib 01.10.2012 в 14:41
2

Структура никогда не может быть нулевой, поэтому вы не можете сравнить ее с нулевой. И структура всегда инициализируется - если не вами, то компилятором со значениями по умолчанию.

    
ответ дан SomebodyYouKnow 01.10.2012 в 14:42
2

Используйте обнуляемый:

ProportionPoint? p1 = null;
if (p1 == null) ...

или

if (!p1.HasValue) ...
    
ответ дан Thorsten Dittmar 01.10.2012 в 14:45
1

В отличие от переменной или значения ссылочного типа, который является ссылкой на ноль или один экземпляр этого типа, структурная переменная или значение является экземпляром структуры , Если у вас есть блок кода, который начинается с {Point myPoint; ...} , и ничто в блоке не закрывается более чем MyPoint (закрытие происходит, когда в блоке есть yield return , или когда лямбда или анонимный метод использует переменную из включающий в себя блок), тогда экземпляр Point возникнет за некоторое время до того, как выполнение войдет в блок, и может прекратить существование в любое время после того, как выполнение покинет блок. В любом контексте, где можно использовать переменную типа структуры, структура существует.

Причина, по которой все типы структур рассматриваются как имеющие конструктор по умолчанию бездействия, заключается в том, что типы структур возникают неявно. Когда выполняется такой оператор, как Point[] myPoints = new Point[100]; , он создает заполненный нулями массив из 100 Point структур; в этом процессе 100 заполненных нулями экземпляров Point мгновенно появляются. В C ++, если у типа есть конструктор, создание массива этого типа вызовет конструктор для каждого элемента массива в последовательности, прежде чем какой-либо код получит доступ к массиву на некоторое время. Если при создании какого-либо элемента возникает исключение, сгенерированный компилятором код будет запускать детерминистский деструктор для каждого элемента, который был успешно создан до того, как сам массив испарится. Хотя это очень мощная функция, включение ее в .net существенно усложнило бы Framework.

    
ответ дан supercat 01.10.2012 в 17:03
0

Я создал метод расширения, который работает только со структурами:

public static bool IsNull<T>(this T source) where T:struct
{
  return source.Equals(default(T));
}

Соглашение о вызовах:

if(myStruct.IsNull())
  DoSomething();

Я понимаю, что на самом деле он не проверяет, является ли он null . Однако, если бы я дал ему более точное имя, такое как IsEmpty или IsDefault , через шесть месяцев я бы забыл, что оно есть, и, увидев список доступных методов, не выберет его. Технически это не нулевая проверка; но концептуально это так.

    
ответ дан toddmo 28.01.2017 в 21:41
-1

Структурные переменные не могут быть нулевыми, можно было бы объявить их как обнуляемые.

    
ответ дан Jamie Keeling 01.10.2012 в 14:43
-1

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

(Например, структура со значением (0,0,0) может быть нетронутой по умолчанию или сохранять исходную точку в трехмерном пространстве.)

Еще один подход, позволяющий избежать этой ложноотрицательной проблемы, - просто добавить еще одно свойство в структуру - например, bool или int - для отслеживания того, действительно ли в нем хранятся данные. Затем любой конструктор, который инициализирует структуру с фактическими данными, устанавливает это значение в true / 1. В структуре по умолчанию это значение по-прежнему будет false / 0, поэтому проверка default(MyStruct) никогда не должна давать ложного отрицания, даже если все остальные данные, хранящиеся в нем, соответствуют значениям по умолчанию.

public Struct MyStruct { 
    public float x { get; private set; }
    public bool initialized { get; private set; }

    public MyStruct(float _x){
        x=_x;
        initialized = true;
    }
}
    
ответ дан PragmaOnce 15.12.2017 в 19:04