Почему назначение члена рассматривается как Func & lt; T, TReturn & gt; а не Action & lt; T & gt; [Дубликат]

+ для следующего брата. Есть ли эквивалент для предыдущего брата?

Вы можете использовать два селектора ax : ! и ?

Там 2 следующие селекторные функции для сиблинга в обычном CSS:

  • + является непосредственным последующим селектором сиблинга
  • ~ является любым последующим селектором сиблинга

. В обычном CSS нет предыдущего селектора sibling.

Однако в ax CSS послепроцессорной библиотеки есть 2 предыдущие селекторные функции:

  • ? - это предыдущий селектор немедленного (напротив +)
  • ! является любым предыдущим селектором (см. ~)

Рабочий пример:

В следующем примере:

  • .any-subsequent:hover ~ div выбирает любой последующий div
  • .immediate-subsequent:hover + div выбирает немедленный последующий div
  • .any-previous:hover ! div выбирает любой предыдущий div
  • .immediate-previous:hover ? div выбирает непосредственный предыдущий div

div {
  display: inline-block;
  width: 60px;
  height: 100px;
  color: rgb(255, 255, 255);
  background-color: rgb(255, 0, 0);
  text-align: center;
  vertical-align: top;
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.6s ease-out;
}

code {
  display: block;
  margin: 4px;
  font-size: 24px;
  line-height: 24px;
  background-color: rgba(0, 0, 0, 0.5);
}

div:nth-of-type(-n+4) {
  background-color: rgb(0, 0, 255);
}

div:nth-of-type(n+3):nth-of-type(-n+6) {
  opacity: 1;
}

.any-subsequent:hover ~ div,
.immediate-subsequent:hover + div,
.any-previous:hover ! div,
.immediate-previous:hover ? div {
  opacity: 1;
}
<h2>Hover over any of the blocks below</h2>

<div></div>
<div></div>

<div class="immediate-previous">Hover for <code>?</code> selector</div>
<div class="any-previous">Hover for <code>!</code> selector</div>
<div class="any-subsequent">Hover for <code>~</code> selector</div>
<div class="immediate-subsequent">Hover for <code>+</code> selector</div>

<div></div>
<div></div>

<script src="https://rouninmedia.github.io/axe/axe.js"></script>

112
задан Michael Petrotta 27 September 2010 в 20:44
поделиться

13 ответов

По моему пониманию, присваивание s = "Hello"; должен только присваивать значение «Hello» для s, но операция не должна возвращать какое-либо значение.

Ваше понимание на 100% неверно. Можете ли вы объяснить, почему вы верите в эту ложную вещь?

Какова аргументация, позволяющая присваивать операторам присваивания значение?

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

В C # существует только один вид выражения который не производит какую-то ценность, а именно, обращение к тому, что набирается как возвращающее пустоту. Каждое другое выражение выражает значение или переменную или ссылку или доступ к свойствам или доступ к событиям и т. Д.

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

Обоснование возможности этой функции состоит в том, что (1) это часто удобно и (2) является идиоматическим в языках типа C.

Можно заметить, что вопрос был умолял: почему этот идиоматический язык на языках C-типа?

Вы должны были бы спросить Денниса Ритчи, но я предполагаю, что задание почти всегда оставляет значение, которое было просто присвоенный в регистре. C - это очень «близкий к машине» вид языка. Это кажется правдоподобным и в соответствии с дизайном C, что есть языковая функция, которая в основном означает «продолжайте использовать значение, которое я только что назначил». Очень легко написать генератор кода для этой функции; вы просто продолжаете использовать регистр, который сохранил значение, которое было назначено.

138
ответ дан Eric Lippert 18 August 2018 в 06:39
поделиться
  • 1
    +1 для интересных размышлений – Mike Burton 27 September 2010 в 21:40
  • 2
  • 3
    @ user437291: Если построение экземпляра не было выражением, вы ничего не могли сделать с построенным объектом - вы не могли его присвоить, вы не могли передать его в метод, и вы не могли бы вызвать какие-либо методы в теме. Было бы бесполезно, не так ли? – Timwi 27 September 2010 в 23:45
  • 4
    Изменение переменной фактически «просто» побочный эффект оператора присваивания, который, создавая выражение, дает значение в качестве своей основной цели. – mk12 24 August 2012 в 23:08
  • 5
    «Ваше понимание на 100% неверно». - Хотя использование ФП на английском языке не является самым большим, его / ее "понимание" это то, что должно быть в этом, что делает его мнением, поэтому это не та вещь, которая может быть «неверна» на 100% ». Некоторые разработчики языка согласны с OP «должен», и уступки не имеют ценности или иным образом запрещают им подвыражения. Я думаю, что это чрезмерная реакция на опечатку = / ==, которая легко устраняется путем отказа от использования значения =, если она не заключена в скобки. например, if ((x = y)) или if ((x = y) == true), но if (x = y) - нет. – Jim Balter 23 July 2015 в 21:01
8
ответ дан ardila 18 August 2018 в 06:39
поделиться
4
ответ дан Dan J 18 August 2018 в 06:39
поделиться
2
ответ дан JamesMLV 18 August 2018 в 06:39
поделиться

Еще один отличный пример использования, я все время использую это:

var x = _myVariable ?? (_myVariable = GetVariable());
//for example: when used inside a loop, "GetVariable" will be called only once
0
ответ дан jazzcat 18 August 2018 в 06:39
поделиться

Дополнительное преимущество, которое я не вижу в ответах здесь, заключается в том, что синтаксис для назначения основан на арифметике.

Теперь x = y = b = c = 2 + 3 означает что-то другое в арифметике, чем язык C-стиля ; в арифметике его утверждение, state , что x равно y и т. д., а в языке C-стиля это инструкция, которая делает x равным y и т. д. после нее .

Это говорит о том, что между арифметикой и кодом все еще существует достаточная связь, которая не имеет смысла отрицать, что естественно в арифметике, если нет веской причины. (Другое дело, что языки C-стиля, взятые из использования символа равенства, - это использование == для сравнения равенства. Здесь, хотя, поскольку right-most == возвращает значение, такая цепочка будет невозможна.)

0
ответ дан Jon Hanna 18 August 2018 в 06:39
поделиться
  • 1
    – Jon Hanna 23 July 2015 в 21:27
  • 2
    @JimBalter нет, ваш второй комментарий на самом деле является аргументом счетчика и звуковым. Мое реплицирование было потому, что ваш первый комментарий не был. Тем не менее, при изучении арифметики мы узнаем, что a = b = c означает, что a и b и c - одно и то же. Изучая язык C-стиля, мы узнаем, что после a = b = c, a и b - это то же, что и c. Разумеется, разница в семантике, как и сам мой ответ, но все же, когда в детстве я сначала научился программировать на языке, который использовал = для назначения, но не позволял a = b = c казаться мне неразумным, хотя ... – Jon Hanna 23 July 2015 в 22:01
  • 3
    ... неизбежно, потому что этот язык также использовал = для сравнения равенства, поэтому в этом случае a = b = c должно означать, что a = b == c означает в языках C-стиля. Я нашел, что цепочка, разрешенная на C, намного интуитивна, потому что я мог бы провести аналогию с арифметикой. – Jon Hanna 23 July 2015 в 22:04

Помимо упомянутых причин (назначение цепочки, set-and-test внутри цикла while и т. д.), правильно используйте инструкцию using, в которой эта функция нужна:

using (Font font3 = new Font("Arial", 10.0f))
{
    // Use font3.
}

MSDN препятствует объявлению одноразового объекта вне оператора using, так как он будет оставаться в области видимости даже после его размещения (см. статью I статьи MSDN).

14
ответ дан Martin Törnwall 18 August 2018 в 06:39
поделиться
  • 1
    Я не думаю, что это действительно цепочки цепей как таковые. – kenny 27 September 2010 в 21:53
  • 2
    @kenny: Э-э ... Нет, но я никогда не утверждал, что это так. Как я уже сказал, в стороне из уже упомянутых причин - который включает в себя цепочку привязки - использование оператора будет намного сложнее в использовании, если бы не тот факт, что оператор присваивания возвращает результат операция присваивания. На самом деле это не связано с цепочки присваивания. – Martin Törnwall 27 September 2010 в 22:32
  • 3
    Но, как отметил Эрик выше, «операторы присваивания не возвращают значение». Это на самом деле просто синтаксис языка используемого оператора, доказательством тому является то, что нельзя использовать выражение «присваивания». в операторе using. – kenny 27 September 2010 в 23:31
  • 4
    @kenny: Извинения, моя терминология была явно неправильной. Я понимаю, что оператор using может быть реализован без языка, имеющего общую поддержку выражений присваивания, возвращающих значение. Это, на мой взгляд, было бы ужасно непоследовательным. – Martin Törnwall 28 September 2010 в 06:29
  • 5
    – configurator 10 September 2011 в 20:37

Во-первых, он позволяет вам цепочки ваших назначений, как в вашем примере:

a = b = c = 16;

. Для другого он позволяет назначать и проверять результат в одном выражении:

while ((s = foo.getSomeString()) != null) { /* ... */ }

Оба варианта, вероятно, сомнительны, но есть определенные люди, которым нравятся эти конструкции.

26
ответ дан Michael Burr 18 August 2018 в 06:39
поделиться
  • 1
    +1 Chaining - не критическая особенность, но приятно видеть, что это просто работает & quot; когда так много чего нет. – Mike Burton 27 September 2010 в 21:41
  • 2
    +1 для цепочки; Я всегда думал об этом как о специальном случае, который обрабатывался языком, а не о естественном побочном эффекте «выражения возвращали значения». – Caleb Bell 30 November 2011 в 19:59
  • 3
    Он также позволяет использовать назначение в возвратах: return (HttpContext.Current.Items["x"] = myvar); – Serge Shultz 12 March 2013 в 11:48

Мое любимое использование выражений присваивания для лениво инициализированных свойств.

private string _name;
public string Name
{
    get { return _name ?? (_name = ExpensiveNameGeneratorMethod()); }
}
27
ответ дан Nathan Baulch 18 August 2018 в 06:39
поделиться

Если присваивание не вернуло значения, строка a = b = c = 16 тоже не работала.

Также возможно иногда использовать такие вещи, как while ((s = readLine()) != null).

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

6
ответ дан sepp2k 18 August 2018 в 06:39
поделиться
  • 1
  • 2
    @ Если ошибка может быть легко предотвращена путем запрета или предупреждения о =, возникающих в выражении, которое не заключено в скобки (не считая parens самого оператора if / while). gcc дает такие предупреждения и тем самым существенно устраняет этот класс ошибок из программ C / C ++, которые скомпилированы с ним. Жаль, что другие авторы компиляторов так мало внимания уделяли этому и нескольким другим хорошим идеям в gcc. – Jim Balter 23 July 2015 в 21:10

Тот факт, что 'a ++' или 'printf ("foo")' может быть полезен либо как автономный оператор, либо как часть большего выражения, означает, что C должен допускать возможность того, что результаты выражения могут или не могут быть использованы. Учитывая это, существует общее представление о том, что выражения, которые могли бы «вернуть» значение, могут также сделать это. Цепочка присваивания может быть немного «интересной» на C и еще более интересной на C ++, если все рассматриваемые переменные не имеют точно такого же типа. Вероятно, такие способы лучше избегать.

1
ответ дан supercat 18 August 2018 в 06:39
поделиться

Я думаю, что основной причиной является (намеренное) сходство с C ++ и C. Приведение оператора assigment (и многих других языковых конструкций) ведет себя так, как их аналоги C ++ просто следуют принципу наименьшего удивления, и любой программист, исходящий из другой кудрявый язык может использовать их, не задумываясь. Было легко выбрать для программистов на С ++ одну из основных целей дизайна для C #.

3
ответ дан tdammers 18 August 2018 в 06:39
поделиться

Разве вы не дали ответ?

Обычный случай, когда используется это свойство оператора присваивания, - это чтение строк из файла ...

string line;
while ((line = streamReader.ReadLine()) != null)
    // ...
42
ответ дан Timwi 18 August 2018 в 06:39
поделиться
  • 1
    +1 Это должно быть одним из самых практических применений этой конструкции – Mike Burton 27 September 2010 в 21:40
  • 2
    Мне очень нравится это для действительно простых инициализаторов свойств, но вы должны быть осторожны и нарисовать свою линию для «простых». низкий для удобочитаемости: return _myBackingField ?? (_myBackingField = CalculateBackingField()); намного меньше, чем проверка на нуль и присвоение. – Thomas G. Mayfield 27 September 2010 в 23:02
Другие вопросы по тегам:

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