2009-08-09 3 views
1

У меня есть приложение, которое открывает ряд DLL-файлов в файловой системе и в GAC и удерживает блокировку этих файлов. Как я могу освободить эти дескрипторы явно, чтобы я мог их перестроить в Visual Studio, не закрывая мое приложение?C#: Почему мое приложение не закрывает свои файлы?

код следующим образом:

private void BuildTabPage_AssemblyTree(string filename, string foldername) 
{ 
    Assembly assembly; 
    try 
    { 
    assembly = Assembly.LoadFrom(filename); 
    } 
    catch (Exception ex) 
    { 
    MessageBox.Show("Error loading assembly " + filename + "\n" + ex.Message); 
    return; 
    } 
    TreeNode tRoot = BuildNode(assembly, foldername); 
    tvAssemblies.Nodes.Add(tRoot); 
    tvAssemblies.ExpandAll(); 

    txtResults.Text = 
    RefsFound.ToString() + " References Located in Filesystem\r\n" + 
    RefsInFramework.ToString() + " References Located in Framework\r\n" + 
    RefsInGac.ToString() + " References Located in GAC\r\n" + 
    RefsNotFound.ToString() + " References Not Found: \r\n\r\n"; 
    foreach (string s in MissingFiles) 
    txtResults.Text += s + "\r\n"; 
} 

private TreeNode BuildNode(Assembly assembly, string foldername) 
{ 
    TreeNode tn = new TreeNode(assembly.GetName().Name); 
    tn.ToolTipText = assembly.FullName + "\n" + assembly.CodeBase; 
    AssemblyName[] assemblies = assembly.GetReferencedAssemblies(); 

    foreach (AssemblyName a in assemblies) 
    { 
    string filename2 = foldername + a.Name + ".dll"; 
    TreeNode tn2; 
    if (System.IO.File.Exists(filename2)) 
    { // File found in folder 
     RefsFound++; 
     Assembly assy = Assembly.LoadFile(filename2); 
     tn2 = BuildNode(assy, foldername); 
    } 
    else if (a.Name.StartsWith("System")) 
    { // Framework assemblies not included 
     RefsInFramework++; 
     tn2 = new TreeNode(); 
     tn2.Text = a.Name; 
     tn2.ForeColor = System.Drawing.Color.Green; 
     tn2.ToolTipText += "\n.NET Framework File"; 
    } 
    else 
    { 
     try 
     { // Find file in GAC 
     Assembly assy = Assembly.Load(a); 
     tn2 = new TreeNode(a.Name); 
     tn.ToolTipText = assembly.FullName + "\n" + assembly.CodeBase + "\nFile detected in GAC"; 
     tn2.Text = "(" + filename2.Substring(filename2.LastIndexOf("\\") + 1) + ")"; 
     tn2.ForeColor = System.Drawing.Color.Green; 
     RefsInGac++; 
     } 
     catch (System.IO.FileNotFoundException) 
     { // File not Found 
     RefsNotFound++; 
     if (!MissingFiles.Contains(a.Name)) 
      MissingFiles.Add(a.Name); 
     tn2 = new TreeNode(); 
     tn2.Text = "(" + filename2.Substring(filename2.LastIndexOf("\\") + 1) + ")"; 
     tn2.ToolTipText = "File Not Found"; 
     tn2.ForeColor = System.Drawing.Color.Red; 
     } 
    } 
    tn.Nodes.Add(tn2); 
    } 

    return tn; 
} 
+2

этот код «запахи» .... BuildNode() имеет несколько обязанностей, не связанных с созданием узла .... –

ответ

6

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

+0

Я не вижу способ добавления AppDomain.Load() по пути и имени файла. Большинство собраний, на которые я нацеливаюсь, не будет в GAC; как загрузить DLL через файл в новый AppDomain? – tsilb

+0

Я предпочел бы создать AppDomain с сборкой, которая содержит BuildTabPage_AssemblyTree() и выполнить метод в созданном AppDomain. Как только вы закончите, вы можете выгрузить созданный AppDomain. Все сборки, загруженные в AppDomain, должны быть выгружены вместе. Я надеюсь, что это может решить вашу проблему. –

+0

AppDomain.Unload не имеет эффекта. Отладчик показывает загружаемые сборки, но не показывает их разгрузку при выгрузке AppDomain. Ручки файлов остаются открытыми. – Triynko

0

Я думаю, если вы настроите ваш AppDomain использовать ShadowCopy он должен работать:

http://blogs.msdn.com/junfeng/archive/2004/02/09/69919.aspx

Эта ссылка занимается ваш вопрос в деталях (если я м вы правильно понимаете): http://blogs.msdn.com/jasonz/archive/2004/05/31/145105.aspx

+0

Это объясняет блокировку файла; но почему он не выгружает файл, когда переменная выходит за рамки? – tsilb

+0

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

+0

Я не думаю, что использование ShadowCopy - хорошая идея. Судя по коду, это приложение завершит копирование очень большого количества сборок, включая многие стандартные системные сборки. Кроме того, у программы не будет возможности обновить свойства сборок, потому что последующие вызовы для загрузки сборки возвратят уже загруженную сборку, а не ту, которая, по-видимому, просто перестроена. –

1

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