Как поймать FileNotFoundException при работе в Mono и отсутствии DLL?

У меня есть рабочий стол Windows 7 x64 с vs2010 и виртуальная установка Linux с mono и monodevelop. Я компилирую следующую программу с помощью vs2010 и запускаю ее на виртуальной машине Linux, и она завершается с ошибкой FileNotFoundException, которая кажется неуловимой. Если я скомпилирую его в виртуальной машине и запущу в Windows, он отлично работает.

Проблема, по-видимому, заключается в том, что моно выбрасывает неперехватываемое исключение перед Main(), когда невозможно загрузить dll. Есть ли способ реструктурировать мою программу или заставить моно, чтобы я мог поймать это исключение?

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

using System;  
#if __MonoCS__  
using Gtk;  
#else  
using System.Windows;  
#endif  
using System.IO;  
using System.Runtime.CompilerServices;  
using System.Collections.Generic;  

namespace Test {

 public static class Program {

  [STAThread]
  public static void Main() {
   try {
    Main2();
   } catch (FileNotFoundException e) {
    Console.WriteLine("Caught FileNotFoundException");
    Console.WriteLine("FileName = {0}", e.FileName);
   }
  }

  [MethodImpl(MethodImplOptions.NoInlining)]
  public static void Main2() {
#if __MonoCS__  
   Application.Init();  
#else  
   Window w = new Window();  
#endif  
  }

 }

}

person zope    schedule 18.08.2010    source источник


Ответы (3)


Вы раскрываете детали реализации JIT-компилятора. Точное время, когда он выдаст исключение для отсутствующей сборки, зависит от того, насколько охотно он транслирует IL в машинный код. Я знаю, что джиттер Microsoft действительно своевременен, он компилирует один метод за раз, непосредственно перед тем, как он собирается выполниться. Хотя на это влияет то, подключен отладчик или нет. Вы мертвы в воде, если Mono, скажем, компилирует весь класс. Джиттер сработает до того, как Main() сможет запуститься.

Возможно, будет лучше, если вы поместите Main2() в другой класс. Лучше всего иметь в наличии сборку, при необходимости муляж.

person Hans Passant    schedule 18.08.2010
comment
Помещение Main2 в другой класс не помогает. То, что вы говорите, имеет смысл, хотя сама идея создания неперехватываемого исключения меня очень расстраивает. Я собираюсь оставить этот вопрос открытым еще немного, чтобы посмотреть, есть ли у кого-нибудь волшебный ответ, но кажется неизбежным, что я дам вам ответ. Спасибо. - person zope; 18.08.2010

Какая DLL не найдена? Я предполагаю, судя по вашему коду, это, вероятно, WinForms. Я не совсем знаком с препроцессором C#, но я думаю, что #if __MonoCS__ может быть более полезным (или может действовать только) как определение препроцессора, то есть он не меняется во время выполнения. Вы можете попробовать определить __MonoCS__ для сборки Mono в настройках проекта и запустить его (я думаю, что VS не определяет это по умолчанию, поэтому, вероятно, он все равно пытается работать с WinForms).

Еще одна вещь, которую можно попробовать, — это закомментировать using System.Windows и весь связанный с ним код (просто используя путь GTK/Mono) и проверить, строится ли он в Windows и работает ли он в обоих. Если это так, то вы сузили список возможных проблем только до этого, и оттуда их будет легче решить.

person ssube    schedule 18.08.2010
comment
В Linux PresentationFramework является первой библиотекой DLL, вызывающей исключение. В Windows это GTK-Sharp. Winforms в этой программе не используется. Весь смысл программы в том, чтобы заставить ее генерировать исключение, чтобы я мог видеть, где уместно его перехватить, поэтому комментирование упомянутого вами кода сделало бы это упражнение невозможным. Если есть лучший способ сделать один .exe способным выбирать между двумя API-интерфейсами во время выполнения, я все уши. - person zope; 18.08.2010
comment
Ах, так вы используете структуру представления, а не формы? Я не думаю, что это сильно меняет. Чтобы один EXE-файл мог работать на любом из них, лучше всего использовать кроссплатформенный пользовательский интерфейс. GTK# подходит и для Windows, поэтому, если это вас не беспокоит, используйте именно его. Первоначально я говорил, что причина, по которой вы получаете исключение, заключается в том, что система не обращает внимания на #if, как вы ожидаете, поэтому их изменение может быть более полезным. Я не знаком с препроцессором С#. Возможно, вам придется выполнить сборку дважды, один раз для Windows и один раз для Linux, если больше ничего не работает. - person ssube; 19.08.2010
comment
Он обращает внимание на #ifs именно так, как я ожидаю. Предполагается, что они заставят его всегда использовать неправильную библиотеку. Я хочу исключения. Весь смысл программы в том, чтобы сгенерировать исключение, чтобы перехватить его. Я хотел использовать эту технику для выбора из множества библиотек во многих ситуациях. GTK и WPF — это просто пример. Кажется, невозможно делать то, что я хочу. Я не хочу заставлять пользователей Windows использовать gtk. - person zope; 19.08.2010

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

Что-то типа:

  • ProgramName.exe — содержит Main точку входа, IPlatformGui и логику, общую для всех платформ.
  • ProgramName.Gtk.dll — содержит GtkGui : IPlatformGui
  • ProgramName.Wpf.dll — содержит WpfGui : IPlatformGui
person Mikayla Hutchinson    schedule 19.08.2010
comment
Я, вероятно, собираюсь прибегнуть к тому, что вы говорите. ТБХ Я не думаю, что у меня есть другой вариант. Я предполагаю, что не могу выбрать здесь более одного ответа? Я хотел бы отдать должное вам обоим. - person zope; 19.08.2010