Использование assemblyresolve для обработки отсутствующих сборок в С#

Я следую методу 3 в http://support.microsoft.com/kb/837908, чтобы динамически загружать сборки в С#. Однако код для меня не работает. В следующем разделе кода автор загружает недостающую сборку только в том случае, если имя отсутствующей сборки является одной из сборок, на которые ссылается приложение.

Когда я запускаю это при отладке, функция вызывается, но недостающая сборка не входит ни в одну из этих ссылок, и поэтому она не задана в моем случае. Любые идеи, почему это происходит? Я не уверен, что эта DLL является С# или родным С++. Может ли это быть, потому что С++ dll не могут быть загружены таким образом? Тогда почему эта функция вызывается для отсутствующей сборки С++? Любые объяснения оцениваются. Если это не работает для сборок С++, на которые ссылаются С#, какие альтернативы?

private Assembly MyResolveEventHandler(object sender,ResolveEventArgs args)
{
    //This handler is called only when the common language runtime tries to bind to the assembly and fails.

    //Retrieve the list of referenced assemblies in an array of AssemblyName.
    Assembly MyAssembly,objExecutingAssemblies;
    string strTempAssmbPath="";

    objExecutingAssemblies=Assembly.GetExecutingAssembly();
    AssemblyName [] arrReferencedAssmbNames=objExecutingAssemblies.GetReferencedAssemblies();

    //Loop through the array of referenced assembly names.
    foreach(AssemblyName strAssmbName in arrReferencedAssmbNames)
    {
        //Check for the assembly names that have raised the "AssemblyResolve" event.
        if(strAssmbName.FullName.Substring(0, strAssmbName.FullName.IndexOf(","))==args.Name.Substring(0, args.Name.IndexOf(",")))
        {
            //Build the path of the assembly from where it has to be loaded.                
            strTempAssmbPath="C:\\Myassemblies\\"+args.Name.Substring(0,args.Name.IndexOf(","))+".dll";
            break;
        }

    }
    //Load the assembly from the specified path.                    
    MyAssembly = Assembly.LoadFrom(strTempAssmbPath);                   

    //Return the loaded assembly.
    return MyAssembly;          
}

Ответ 1

Термин "сборка" означает не только любую DLL; это означает, что DLL создана с .NET и для .NET. Его также часто называют "управляемым кодом", который примерно означает, что вы используете сборщик мусора .NET, а не обычную кучу С++ для управления памятью. (Я упрощаю, есть также "сборки смешанного режима", которые разрешаются таким образом, хотя они используют сочетание управляемого и неуправляемого кода. И "управляемый" означает совсем немного больше, чем просто управление памятью.)

Не имеет значения, написана ли ваша ссылка на сборку на С++/CLI или на С#. С++/CLI часто путают с С++, но на самом деле это другой язык с дополнительными возможностями для использования управляемой среды. Если вы скомпилируете что-то С++ 'ish с помощью переключателя /clr, это С++/CLI, а не С++.

Есть три исправления с указанной статьей базы знаний, которые вам нужно понять.

  • "Метод 3" в статье не учитывает косвенные ссылки. То есть сборки, на которые ссылаются узлы, ссылающиеся на вашу основную сборку. Это, вероятно, укусит вас прямо сейчас.

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

  • Если вы имеете дело с кодом С++/CLI, вероятность того, что вам также нужно загрузить некоторые неуправляемые DLL на С++, с которыми была связана предыдущая ссылка. Это делается с использованием обычного порядка поиска Windows DLL и вне вашего резольвера. Но это не ваша проблема, пока вы видите, что обработчик введен для конкретной DLL. Нормальный тип C или С++ DLL, который не имеет ничего общего с .NET, вообще не будет отображаться в обработчике.