Первый левый операнд сломан?
В соответствии с этим здесь
левый будет оцениваться до правого...
но у меня есть проект, где:
int[] df = null; //GetDataFrame()
int xIndex = 12; //GetLearningIndex()
df[0] = 1 % GetLearningIndex();
и я понял, когда GetDataFrame возвращает ноль, а GetLearningIndex возвращает ноль, я получаю System.DivideByZeroException
Я ожидал бы, согласно как System.NullReferenceException
... есть причина почему??
3 ответа
Здесь есть некоторая путаница... сначала оцениваются части LHS оператора присваивания. В частности, выражения df
а также 0
будет оцениваться раньше GetLearningIndex
, но назначение элемента массива (включая проверку индекса) происходит только после вычисления результата.
Вот пример, показывающий некоторые дополнительные детали:
using System;
public class Test
{
private int[] array = new int[10];
static void Main()
{
Test instance = null;
// This would throw a NullReferenceException
// because instance is null at the start of the statement.
// ExecuteSideEffect never gets called.
// instance.array[100] = ExecuteSideEffect(() => instance = new Test());
instance = new Test();
// This would throw an IndexOutOfBoundsException
// because instance.array is evaluated before ExecuteSideEffect.
// The exception is only thrown when the assignment is performed.
// instance.array[100] = ExecuteSideEffect(() => instance.array = new int[1000]);
int index = 5;
// This modifies array index 5 because index is evaluated
// before EvaluateSideEffect
instance.array[index] = ExecuteSideEffect(() => index = 1);
Console.WriteLine(instance.array[5]); // 10
}
private static int ExecuteSideEffect(Action action)
{
action();
return 10;
}
}
Итак, в заявлении этой формы:
arrayExpression[indexExpression] = valueExpression;
порядок выполнения:
- оценивать
arrayExpression
, Там нет проверки, что результат не является нулевым, но вычисление выражения может сам броситьNullReferenceException
, - оценивать
indexExpression
, На этом этапе проверка массива не выполняется. - оценивать
valueExpression
- Установите элемент массива, выраженный с использованием результатов шагов 1 и 2, на результат шага 3. Здесь выполняются проверки, что ссылка на массив не равна нулю и индекс массива действителен.
На данный момент, насколько я могу судить, это плохо указано - я подниму вопрос, чтобы посмотреть, сможем ли мы это исправить в стандарте ECMA C# 5.
Левые операнды вычисляются первыми, когда дело доходит до математических операций. В вашем случае вы вызываете метод, который возвращает значение: GetLearningIndex()
, какое значение всегда будет оцениваться перед любой математической операцией, с которой вы его используете.
Вы на самом деле ссылаетесь на неправильный документ. Как уже упоминалось, оператор присваивания, наконец , оценивается. Таким образом, ваш метод-вызов, а также математическая операция (%
оценивается до того, как присвоение уступает в DivideByZeroException
,
Кроме того, оператор присваивания оценивается справа налево, в отличие от всех других двоичных, которые оцениваются слева направо:
За исключением операторов присваивания, все бинарные операторы являются левоассоциативными, что означает, что операции выполняются слева направо. Например, x + y + z оценивается как (x + y) + z. Операторы присваивания и условный оператор (?:) являются ассоциативными справа, что означает, что операции выполняются справа налево. Например, x = y = z оценивается как x = (y = z).