2017-01-21 5 views
27

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

public static Boolean Foo(Boolean x) 
{ 
    Boolean a = false; 
    if(x) 
    { 
     a = true; 
    } 
    else 
    { 
     try 
     { 
      SomethingThatMightThrow(); 
      Assert.IsFalse(a); 
      return a; 
     } 
     catch(Exception) 
     { 
      a = true; 
     } 
    } 

    if(a) 
    { 
     return x; 
    } 
} 

Непосредственное исправление просто удалить заявление if(a) сторожевых полностью и просто return x сразу - но почему компилятор жалуется, даже если он должен быть в состоянии статический доказать все возможные пути коды ударит return заявления? Реально, нет никаких петель, которые часто являются основной причиной того, что он не докажет return -ness.

Я использую VS2015 Update 3.

+0

Что делать, если в конце этого кода _printUsage_ является ложным? Помните, что компилятор не может догадаться, что во время выполнения ваша переменная всегда истинна, когда вы достигаете точки выхода – Steve

+0

@Steve Но 'printUsage' никогда не будет ложным к концу функции' Main' - если это когда-либо 'false', тогда' return 'statement внутри' try {} 'будет соблюдаться. – Dai

+4

Если переменные всегда имеют значение true, зачем использовать переменную в первую очередь? Удалите условие и всегда печатайте его, если вы еще не вернулись из метода. – knittl

ответ

52

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

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

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

@PetSerAl уже цитировал соответствующую формулировку в спецификации # языке C:

8,1 Конечные точки и достижимость

[...]

Чтобы определить, достигнут ли конкретный оператор или конечная точка, компилятор выполняет анализ потока в соответствии с правилами достижимости, определенными для каждого оператора. Анализ потока учитывает значения константных выражений (§7.19), которые управляют поведением операторов, но возможные значения непостоянных выражений не рассматриваются. Другими словами, для целей анализа потока управления считается, что непостоянное выражение данного типа имеет любое возможное значение этого типа.

Это часть последней опубликованной спецификации языка, единственной для C# 5.0. Версия, которую вы используете, C# 6.0 (это то, что предлагает VS2015), пока не имеет опубликованной спецификации, поэтому вполне возможно, что формулировка будет немного отличаться, но, как показал ваш компилятор, фактически это же правило все же применяется.

+0

Это отличный ответ, но поскольку этот вопрос стал настолько популярен, вы можете подумать о его улучшении, ссылаясь на соответствующую часть спецификации языка C#. [PetSerAl уже цитировал это в комментарии] (http://stackoverflow.com/questions/41777289/why-does-the-compiler-complain-that-not-all-code-paths-return-a-value-when- IC# comment70745748_41777289). –

+0

@CodyGray OP использует VS2015, который реализует C# 6, который, насколько я знаю, до сих пор не имеет спецификации языка. – hvd

+0

@hvd VS2015 использует любую версию C#, которую вы выбираете для своего проекта, и, похоже, нет ничего особенного в вопросе C# 6. – BartoszKP

6

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

Это может быть неправильное решение, но при работе с сложным кодом возвращаемое значение может быть нечетким. Итак, программист вынужден вернуть его.

Ваш пример может быть сведена к минимуму, как это:

public static Int32 Main(String[] args) 
{ 
    var printUsage = true; 
    if (printUsage) 
    { 
     return 0; 
    } 

    // return nothing, so compiler is not happy 
} 

все еще получаю ошибку.

ПРИМЕЧАНИЕ: если вы используете Resharper, он будет выполнять анализ вы хотите, и, соответственно, предупреждает:

if (printUsage)   // Warning: expression is always true 
+1

Интересно - хотя согласно статье, которую @steve связывает с (Эриком Липпертом, не менее!), Он говорит, что компилятор вычисляет достижимость с использованием констант времени компиляции - поэтому в соответствии с этой статьей компилятор не должен сообщать о каких-либо проблемах с вашей главной 'либо (http://blog.coverity.com/2013/11/06/c-reachability/#.WIMgWIWcGdI) – Dai

+1

@Dai' printUsage' не является константой времени компиляции. – hvd

+1

Более того, даже 'printUsage' объявлен членом класса static readonly', он все равно будет жаловаться. –

26

Это время выполнения против времени компиляции

Ваш пример слишком сложно. Это не будет компилироваться либо:

static int Test() 
{ 
    bool f = true; 
    if (f) 
    { 
     return 1; 
    } 
    else 
    { 
     //Not all code paths return a value 
    } 
} 

С другой стороны, это:

static int Test() 
{ 
    if (true) 
    { 
     return 1; 
    } 
    else 
    { 
     //No error 
    } 
} 

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

 Смежные вопросы

  • Нет связанных вопросов^_^