Судя по контексту, в котором загружается сборка (контекст «LoadNeither»), некоторые разработчики могут делать что-то вроде загрузки сборки, которая была внутренне упакована как ресурс в ваше приложение. Если вы сделаете это, вы будете использовать обработчик событий AppDomain.CurrentDomain.AssemblyResolve, чтобы ваше приложение могло указать, где .NET должен получать любую конкретную сборку, которая ему нужна.
Мой ответ не объяснит махинации, как это сделать, - но я упоминаю об этом, потому что этот процесс привел непосредственно к той же самой ошибке, с которой столкнулся оригинальный постер. Как упоминает Эрик Липперт, типы создаются для каждой сборки. Поэтому, если вы загружаете отдельную сборку более одного раза, один и тот же определенный класс будет отображаться как разные классы - даже если визуальный осмотр показывает, что они кажутся одинаковыми.
Мы видели случаи, когда .NET вызывал ResolveEventHandler более одного раза для одной и той же DLL. Я не уверен, почему .NET иногда делает это (это произошло на некоторых машинах, но не на всех машинах). Но чтобы решить эту проблему, нам нужно было сохранить глобальный список дескрипторов для загруженных сборок, чтобы, если .NET захотел загрузить сборку снова, мы вернули дескриптор той же сборке, которая была первоначально загружена, вместо загрузки другой копии в память .
Я включил код, который вызвал у нас проблему, и примечания о том, как правильно ее решить.
public void AppStartup (object sender, StartupEventArgs e)
{
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}
public System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string dllName = args.Name.Contains(',') ? args.Name.Substring(0, args.Name.IndexOf(',')) : args.Name.Replace(".dll", "");
dllName = dllName.Replace(".", "_");
if (dllName.EndsWith("_resources")) return null;
System.Resources.ResourceManager rm = new System.Resources.ResourceManager(GetType().Namespace + ".Properties.Resources", System.Reflection.Assembly.GetExecutingAssembly());
byte[] bytes = null;
try
{
bytes = (byte[])rm.GetObject(dllName);
}
catch (Exception ex)
{
}
if (bytes != null)
{
// the following call will return a newly loaded assembly
// every time it is called
// if this function is called more than once for the same
// assembly, you'll load more than one copy into memory
// this can cause the InvalidCastException
// instead of doing this, you keep a global list of loaded
// assemblies, and return the previously loaded assembly
// handle, instead of loading it again
return System.Reflection.Assembly.Load(bytes);
}
return null;
}