условие .net не выполняется должным образом

#.net #conditional #try-catch #throw

#.net #условные операторы #попробуйте-поймайте #выбрасывать

Вопрос:

У меня есть следующий простой блок кода

   var assmSpec = util.ASSEMBLYFOLDER   task.AssemblyName; // evals to valid fileSpec
  if (!File.Exists(assmSpec))
      throw new TaskException(string.Format(
          "Assembly [{0}] cannot be located.", assmSpec));
  

Поскольку сборка, на которую ссылается assmSpec, действительно существует ( File.Exists() значения равны true), я ожидаю, что исключение не будет выдано. Но это так. код переходит к инструкции throw. Для отладки я изменил код, чтобы читать:

   var assmSpec = util.ASSEMBLYFOLDER   task.AssemblyName; // evals to valid fileSpec
  var asmExists = File.Exists(assmSpec);
  if (!asmExists)
      throw new TaskException(string.Format(
          "Assembly [{0}] cannot be located.", assmSpec));
  

Здесь asmExists присваивается значение true, и код все еще переходит в throw.

Затем я изменил код, чтобы читать:

   var assmSpec = util.ASSEMBLYFOLDER   task.AssemblyName; // evals to valid fileSpec
  if (!File.Exists(assmSpec) amp;amp; File.Exists(assmSpec))
      throw new TaskException(string.Format(
         "Assembly [{0}] cannot be located.", assmSpec));
  

и снова, код все еще попадает в throw. Здесь явно что-то не так. У кого-нибудь есть объяснение? Я делаю здесь что-то действительно явно глупое?

черт возьми, этот код находится в методе, который также имеет конструкцию try — catch — finally, но он находится перед всеми ними (перед попыткой) …


Полный метод является:

   public void StartProcess(Task task)
    {
        log.Write(log.Level.Debug, string.Format(
            "TaskWorker.StartProcess {0} process",
            task.Name), task.Name);
        WorkerMessageManager.MsgArrvdWorkerHndlr  = MsgArrvdWorkerHndlr;
        var tskName = task.Name;
        var assmSpec = util.ASSEMBLYFOLDER   task.AssemblyName;
        if (!File.Exists(assmSpec))
            throw new TaskException(string.Format(
                "Assembly [{0}] cannot be located.", assmSpec));

        try
        {
            WorkerMessageManager.NotifyWorker(new ProgressTaskMessage(
                                    tskName, "", tskName   "  starting..."));
            // -------------------------------------------
            Assembly dA;
            try { dA = Assembly.LoadFrom(assmSpec); }
            catch(FileNotFoundException nfX)
            { throw new TaskException(string.Format(
                "Assembly [{0}] cannot be located.", assmSpec), 
                nfX); }
            // -------------------------------------------
            var iTsk = (IExecuteTasks)dA.CreateInstance(task.ClassName);
            if (iTsk == null)
                throw new TaskException(
                    string.Format("Unable to instantiate {0} from {1}",
                        task.ClassName, task.AssemblyName));

            if (iTsk.TaskName != tskName) // do not execute if names do not match
                throw new TaskNameMismatchException(string.Format(
                    "CHECK CONFIGURATION SETTINGS,  Data Task Name Mismatch.{0}"  
                    "Task name defined in TaskScheduler.config [{1}], {0} does "  
                    "not match name [{2}] as defined in Task Logic assembly: {3}.{4}",
                        sNL, tskName, iTsk.TaskName, task.AssemblyName, 
                        task.ClassName),  tskName, iTsk.TaskName);
            // -------------------------------------------
            iTsk.DataImportProgressEvent  = OnProgressReport;
            iTsk.ProcessCompletedEvent  = OnProcessCompleted;
            iTsk.GeneralEvent  = OnGeneralEvent;
            // -----------------------------------
            log.Write(log.Level.Debug, string.Format(
                  "{0} process Started", task.Name),
                  task.Name);
            if (task.JobQueue.HasJobReady)
                iTsk.StartTask(JobQueues.Instance.DeQueue(tskName));
            else iTsk.StartTask(); 
            log.Write(log.Level.Debug, string.Format(
                  "{0} process Completed", task.Name),
                  task.Name);
        }
        catch (TaskNameMismatchException inmX)
        { log.Write(log.Level.Warn, inmX.Message, tskName, inmX); }

        catch (BpaTaskException mX)
        {
            var errMsg = string.Format(
                "Error in Data Import StartProcess(). "   sNL  
                "Exception {0}: {1}, "   sNL  
                "Stack Trace: {2}",
                mX, mX.Message, mX.StackTrace); 
            log.Write(log.Level.Error, errMsg, 
                        task.Name, mX);
        }

        catch(Exception X)
        {
            var errMsg = string.Format(
                "Error in Data Import StartProcess(). "   sNL  
                "Exception {0}: {1}, "   sNL  
                "Stack Trace: {2}",
                X, X.Message, X.StackTrace);
            log.Write(log.Level.Error, errMsg, task.Name, X);

            // WorkerMessageManager.NotifyWorker(new ImportFailMessage(X));
            // This throw instruction causes the Scheduler service to stop alltogether
            // I'm Removing the throw for now, because it seems inappropriate to 
            //          kill the whole service..
            throw;
        }

        finally
        {
            task.IsRunning = false;
            WorkerMessageManager.MsgArrvdWorkerHndlr -= MsgArrvdWorkerHndlr;
        }
    }
  

Комментарии:

1. О, пожалуйста, используйте фигурные скобки даже для if, в котором есть только один оператор.

2. проверьте присвоенное переменной assSpec значение…

3. да, присвоенное значение является правильным, но что более важно, когда я выполняю отладку во втором блоке, присвоенное значение asmExists равно true…

4. Это помогло бы увидеть больше кода, окружающего этот фрагмент.

5. Иногда я сталкиваюсь с невозможными ситуациями, подобными этой, и обнаруживаю, что закрытие Visual Studio, затем перезапуск и выполнение полной перестройки решат проблему. Я не видел этого в VS 2010, но более ранние версии периодически выполняли это.

Ответ №1:

Убедитесь, что после if () инструкции в той же строке нет текста (кода или точки с запятой). Наиболее вероятная причина заключается в том, что «throw» на самом деле не находится «внутри» инструкции if, поэтому он всегда выполняется.

Убедитесь, что вы отлаживаете отладочную сборку — вы можете получить нечетные значения, сообщаемые в отладчике для сборки ВЫПУСКА, из-за чего может показаться, что переменная имеет значение true, хотя на самом деле это false.

При некоторых обстоятельствах также возможно (хотя обычно только с такими вещами, как ссылки на предварительно скомпилированные библиотеки DLL или поврежденные файлы pdb) просматривать код, отличный от того, который вы отлаживаете, создавая впечатление, что изменения, которые вы вносите в исходный код, игнорируются. Выполните сборку> Очистить, убедитесь, что выполняемая вами сборка больше не присутствует на диске, а затем перестройте ее, чтобы убедиться, что она актуальна и синхронизирована с вашим исходным кодом.

Комментарии:

1. хорошие предложения, перепробовал их все. Даже переместил все кодовое решение на новую (другую) машину в другой среде…. получаем такое же поведение.

2. В этом случае я бы попытался сократить код до минимально воспроизводимой формы и убрать все, что может повлиять на результаты (убедитесь, что есть только одно место, где возникает это исключение, устраните вложенные попытки / перехваты, используйте bool вместо var, задайте фиксированный путь к файлу, который постоянно существует и не будет открыт (или запущен) в данный момент и т.д. Это должно привести вас к точке, где вы сможете определить, что вызывает такое поведение, и это может оказаться чем-то простым, например, на самом деле выполняется второй бросок и выдается исключение FNF, потому что файл открыт.

Ответ №2:

Я только что попробовал что-то подобное, и у меня это отлично работает. Вы пробовали это, используя блок инструкций вместо одной строки броска?

Компилятор может быть сбит с толку, и, возможно, потребуется перезапустить. Это не является чем-то неслыханным. :/

Комментарии:

1. смотрите мои комментарии выше.. Перезагрузили и даже перенесли все решение на другой компьютер. И не может использовать блок using . Какой объект я бы использовал? Файл. Exists() — это статический метод.

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

3. ааа. извините, пропустил это. Но нет, использование фигурных скобок не влияет на поведение.

Ответ №3:

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

  1. значение path равно нулю или является пустой строкой
  2. Файл не существует
  3. ОС считает, что файл на самом деле является каталогом
  4. Учетная запись, пытающаяся получить доступ к файлу, не имеет прав на чтение.
  5. Генерируется какое-либо другое внутреннее исключение NotSupportedException, SecurityException, IOException или UnauthorizedAccessException.

Проблема в том, что все эти потенциальные ошибки скрыты. Я бы предложил вместо этого попробовать FileInfo класс:

 var fileInfo = new FileInfo( assmSpec );
if ( !fileInfo.Exists )
    throw new TaskException( ...
  

Конструктор в FileInfo вернет вам одно из нескольких исключений, которое может дать вам больше информации о проблеме.