Почему я не должен всегда использовать nullable типы в C#

Правильная формула должна быть (20px / cos(45deg)) * N. Затем вы можете просто сделать background-size 200% 100% (вдвое больше, чем элемент) и легко анимировать слева направо:

li {
  display: inline-block;
  width: calc( (20px / 0.707) * 3); /*cos(45deg) = 0.707*/
  height: 50px;
  margin-bottom:10px;
  background-color: blue;
  background-image: repeating-linear-gradient(-45deg, transparent, transparent 10px, black 10px, black 20px);
  background-size: 200% 100%;
  background-color: blue;
  animation: loading-slide 3s linear infinite;
}

@keyframes loading-slide {
  from {
    background-position: left;
  }
  to {
    background-position: right;
  }
}

.alt li {
  width: calc( (20px / 0.707) * 6);
}
  • test
  • test
  • test
  • test
[ 1191]

Вы можете рассмотреть любую степень и скорректировать формулу по мере необходимости. (20px / cos(90deg - |Xdeg|)) * N с X между -90deg и 90deg

Пример с -60deg

li {
  display: inline-block;
  width: calc((20px / 0.866) * var(--n,3)); /*cos(30deg) = 0.866*/
  height: 50px;
  margin-bottom:10px;
  background-color: blue;
  background-image: repeating-linear-gradient(-60deg, transparent, transparent 10px, black 10px, black 20px);
  background-size: 200% 100%;
  background-color: blue;
  animation: loading-slide 3s linear infinite;
}

@keyframes loading-slide {
  from {
    background-position: left;
  }
  to {
    background-position: right;
  }
}

.alt li {
  --n:6;
}
  • test
  • test
  • test
  • test

Пример с 30deg

li {
  display: inline-block;
  width: calc((20px / 0.5) * var(--n,8)); /*cos(60deg) = 0.5*/
  height: 50px;
  margin-bottom:10px;
  background-color: blue;
  background-image: repeating-linear-gradient(30deg, transparent, transparent 10px, black 10px, black 20px);
  background-size: 200% 100%;
  background-color: blue;
  animation: loading-slide 3s linear infinite;
}

@keyframes loading-slide {
  from {
    background-position: left;
  }
  to {
    background-position: right;
  }
}

.alt li {
  --n:12;
}
  • test
  • test
  • test
  • test

Пример с 80deg

[ 1173]
li {
  display: inline-block;
  width: calc((20px / 0.9848) * var(--n,8)); /*cos(10deg) = 0.9848*/
  height: 50px;
  margin-bottom:10px;
  background-color: blue;
  background-image: repeating-linear-gradient(80deg, transparent, transparent 10px, black 10px, black 20px);
  background-size: 200% 100%;
  background-color: blue;
  animation: loading-slide 3s linear infinite;
}

@keyframes loading-slide {
  from {
    background-position: left;
  }
  to {
    background-position: right;
  }
}

.alt li {
  --n:12;
}
  • test
  • test
  • test
  • test

Вы можете четко определить тривиальный случай, когда X=+/-90deg (вертикальные полосы) и у нас будет cos(0)=1, таким образом, формула будет 20px * N. Также, когда X=0 (горизонтальные полосы) у нас будет cos(90deg) = 0, и любая ширина будет работать, так как нет вертикального шаблона (формула больше не определяется)

li {
  display: inline-block;
  width: calc(20px * var(--n,8)); 
  height: 50px;
  margin-bottom:10px;
  background-color: blue;
  background-image: repeating-linear-gradient(90deg, transparent, transparent 10px, black 10px, black 20px);
  background-size: 200% 100%;
  background-color: blue;
  animation: loading-slide 3s linear infinite;
}

@keyframes loading-slide {
  from {
    background-position: left;
  }
  to {
    background-position: right;
  }
}

.alt li {
 background-image:repeating-linear-gradient(0deg, transparent, transparent 10px, black 10px, black 20px);
}
[ 119]

Как насчет значения за пределами [-90deg,90deg]?

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

Пример: 110deg совпадает с -70deg

li {
  display: inline-block;
  width: calc((20px / 0.9396) * var(--n,8)); /*cos(20deg) = 0.9396*/
  height: 50px;
  margin-bottom:10px;
  background-color: blue;
  background-image: repeating-linear-gradient(110deg, transparent, transparent 10px, black 10px, black 20px);
  background-size: 200% 100%;
  background-color: blue;
  animation: loading-slide 3s linear infinite;
}
.alt li {
  --n:12;
  background-image: repeating-linear-gradient(-70deg, transparent, transparent 10px, black 10px, black 20px);
}

@keyframes loading-slide {
  from {
    background-position: left;
  }
  to {
    background-position: right;
  }
}
  • test
  • test
  • test
  • test
[1156]

Пример: -150deg совпадает с 30deg

li {
  display: inline-block;
  width: calc((20px / 0.5) * var(--n,4)); /*cos(60deg) = 0.5*/
  height: 50px;
  margin-bottom:10px;
  background-color: blue;
  background-image: repeating-linear-gradient(-150deg, transparent, transparent 10px, black 10px, black 20px);
  background-size: 200% 100%;
  background-color: blue;
  animation: loading-slide 3s linear infinite;
}
.alt li {
  --n:6;
  background-image: repeating-linear-gradient(30deg, transparent, transparent 10px, black 10px, black 20px);
}

@keyframes loading-slide {
  from {
    background-position: left;
  }
  to {
    background-position: right;
  }
}
  • test
  • test
  • test
  • test

в основном мы добавляем / удаляем 180deg, пока не попадем внутрь [ 1140], чтобы можно было применить формулу.


Проверьте этот ответ для получения более подробной информации о том, как background-size / background-position работает: https://stackoverflow.com/a/51734530/8620333


[1164 ] Другой подход

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

li {
  display: inline-block;
  width: calc( 20px * 3); /* it's only 20px * N */
  height: 50px;
  margin-bottom:10px;
  background-color: blue;
  position:relative;
  z-index:0;
  overflow:hidden
}
li::before {
  content:"";
  position:absolute;
  top:0;
  bottom:0;
  left:0;
  width:400%;
  /*we keep 0deg in the gradient*/
  background-image: repeating-linear-gradient(90deg, transparent, transparent 10px, black 10px, black 20px);
  transform:skewX(30deg);
  transform-origin:bottom left;
  animation: loading-slide 4s linear infinite;
}

@keyframes loading-slide {
  to {
    transform: translateX(-50%) skewX(30deg);
  }
}

.alt li {
  width: calc( 20px * 6);
}
  • test
  • test
  • test
  • test

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

При таком подходе у вас также будет лучшая производительность, поскольку вы будете анимировать преобразование вместо background-size.

Больше примеров:

li {
  display: inline-block;
  width: calc( 20px * var(--n,3)); /* it's only 20px * N */
  height: 50px;
  margin-bottom:10px;
  background-color: blue;
  position:relative;
  z-index:0;
  overflow:hidden
}
li::before {
  content:"";
  position:absolute;
  top:0;
  bottom:0;
  left:-400%;
  right:-800%;
  /*we keep 0deg in the gradient*/
  background-image: repeating-linear-gradient(90deg, transparent, transparent 10px, black 10px, black 20px);
  transform:skewX(var(--d,30deg));
  animation: loading-slide 12s linear infinite;
}

@keyframes loading-slide {
  to {
    transform: translateX(-50%) skewX(var(--d,30deg));
  }
}
  • test
  • test
  • test
  • test
  • test
  • test
  • test
  • test

35
задан Josh Lee 7 April 2010 в 10:11
поделиться

6 ответов

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

List<int> list = new List<int>()
int c = list.Count;

Это всегда допустимо. Невозможно не инициализировать c . Если бы он был превращен в int? , вы бы фактически сказали читателям кода: «это значение может быть нулевым. Обязательно проверьте перед использованием». Но мы знаем, что этого никогда не случится, так почему бы не раскрыть эту гарантию в коде?

Вы абсолютно правы в случаях, когда значение является необязательным. Если у нас есть функция, которая может возвращать или не возвращать строку, верните ноль. Не возвращайте string.Empty (). Не возвращайте «магические значения».

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

Если вы можете конкретно гарантировать, что это значение всегда будет действительным, тогда зачем выбрасывать эту информацию? Это то, что вы делаете, делая это обнуляемым типом. Теперь значение может существовать или не существовать, и любой, кто его использует, должен будет обрабатывать оба случая. Но вы знаете, что только один из этих случаев возможен в первую очередь. Поэтому сделайте пользу пользователям вашего кода и отразите этот факт в своем коде.

46
ответ дан 27 November 2019 в 07:07
поделиться

Хотя нулевые значения могут быть удобны для использования в качестве «еще не инициализированных» или «неуказанных» значений, они делают код более сложным, в основном из-за того, что вы перегружаете значение null , а также переменная (число-или-ноль против просто-числа).

Значения NULL предпочитают многие разработчики баз данных и программисты баз данных SQL, но с небольшим изменением в мышлении о проблема, которую вы можете устранить с нулевыми значениями и на самом деле иметь более простой и надежный код (например, не беспокойтесь о NullReferenceException s).

Там на самом деле большой спрос на "T!" оператор, который делает любой ссылочный тип ненулевым, аналогично тому, как "T?" делает типы значений обнуляемыми, и Андерс Хейлсберг, изобретатель C #, хотел бы, чтобы он включил эту способность.

См. Также вопрос, Почему в C # и java присутствует «ноль»?

1
ответ дан 27 November 2019 в 07:07
поделиться

Потому что неудобно всегда проверять, является ли тип, допускающий значение NULL, NULL .

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

// nice and simple, this will always work
int a = myInt;

// compiler won't let you do this
int b = myNullableInt;

// compiler allows these, but causes runtime error if myNullableInt is null
int c = (int)myNullableInt;
int d = myNullableInt.Value;    

// instead you need to do something like these, cumbersome and less readable
int e = myNullableInt ?? defaultValue;
int f = myNullableInt.HasValue ? myNullableInt : GetValueFromSomewhere();
9
ответ дан 27 November 2019 в 07:07
поделиться

Я думаю, что разработчики языка считают, что «ссылочные типы, допускающие значение NULL по умолчанию» было ошибкой, и что значение по умолчанию, не допускающее значения NULL, является единственным разумным значением по умолчанию, и вам следует отказаться от использования NULL. (Так обстоит дело во многих современных функциональных языках.) «Null» обычно доставляет массу неприятностей.

3
ответ дан 27 November 2019 в 07:07
поделиться

Кажется, у вас есть 2 разных вопроса ...

Зачем мне вообще использовать в C # типы данных, не допускающие значения NULL?

Просто, потому что данные типа значения, на которые вы полагаетесь, гарантированно компилятором действительно имеют значение!

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

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

Конечно, когда ваши данные поступают откуда угодно, кроме вашей программы, тогда все ставки выкл. Лучший пример - из базы данных. Поля базы данных могут иметь значение null , поэтому вы хотите, чтобы ваша программная переменная имитировала это значение, а не просто создавала «магическое» значение (например, -1, 0 или что-то еще), которое «представляет» null . Вы делаете это с типами, допускающими значение NULL.

поэтому вы хотите, чтобы ваша программная переменная имитировала это значение, а не просто создавала «магическое» значение (например, -1, 0 или что-то еще), которое «представляет» null . Вы делаете это с типами, допускающими значение NULL.

поэтому вы хотите, чтобы ваша программная переменная имитировала это значение, а не просто создавала «магическое» значение (например, -1, 0 или что-то еще), которое «представляет» null . Вы делаете это с типами, допускающими значение NULL.

3
ответ дан 27 November 2019 в 07:07
поделиться

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

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

0
ответ дан 27 November 2019 в 07:07
поделиться
Другие вопросы по тегам:

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