ReflectionTypeLoadException 和 COM 互操作
ReflectionTypeLoadException and COM-Interop
我有一个 .Net4 程序集,它公开了一个抽象的基础 class。在同一个程序集中,我有一些代码反映了一个文件夹中的所有文件,以构建一个 classes 的列表,继承该基础 class。这是重要的例程
private JsonTextWriter GetAvailableServices(JsonTextWriter writer, string path)
{
try
{
writer.WriteStartArray();
writer = new DirectoryInfo(path).GetFiles(FileFilter)
.Where(f => IsAssembly(f.FullName))
.Select(f => Assembly.LoadFile(Path.Combine(path, f.Name)))
.SelectMany(a => GetLoadableTypes(a))
.Where(p => typeof(ServiceProxy).IsAssignableFrom(p) && !p.IsAbstract)
.Select(a0 => new { Instance = Activator.CreateInstance(a0), ClassName = a0.ToString() })
.Aggregate(writer, (s, v) =>
{
s.WriteStartObject();
s.WritePropertyName(ClassnameLabel);
s.WriteValue(v.ClassName);
s.WritePropertyName(DescriptionLabel);
s.WriteValue(((ServiceProxy)v.Instance).Description);
s.WriteEndObject();
return s;
});
}
catch { Exception ex; }
finally
{
writer.WriteEndArray();
}
return writer;
}
private IEnumerable<Type> GetLoadableTypes(Assembly assembly)
{
try
{
return assembly.GetTypes();
}
catch (ReflectionTypeLoadException e)
{
return e.Types.Where(t => t != null);
}
}
我有一个运行这段代码的单元测试,目标是一个特定的文件夹,它一切正常,返回一个 classes 列表,继承基础 class 作为 JSON。
以上代码位于要从 COM (VB6) 组件调用的程序集中。如果我现在从 COM 调用相同的代码,以单元测试所针对的同一文件夹为目标,我会收到反射错误,并且加载程序信息报告它无法加载包含上述代码的程序集。这只发生在 GetTypes()
调用的 GetLoadableTypes
例程中,当我反思包含 class 的程序集时,它确实继承了基础 class.
这听起来几乎像是只有在涉及 COM 时才会出现的重入问题。我想我可以将抽象基础 class 放入另一个程序集,但想知道是否还有其他事情发生。
非常感谢收到的任何解释或指示
错误信息:
ReflectionTypeLoadException "Unable to load one or more of the
requested types. Retrieve the LoaderExceptions property for more
information."
并且在 LoaderExceptions 中:
"Could not load file or assembly 'IfxGenDocService, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null' or one of its dependencies. The
system cannot find the file specified.":"IfxGenDocService,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
EDIT1:我做了一些改动,将基础 class 提取到它自己的程序集中,但我仍然遇到同样的错误。也许相关的是,我有一个测试程序集,其中包含 3 个 classes 继承基础 class。我得到 3 个 LoaderExceptions(与上面报告的一样。我假设每个 class.
有 1 个
问题出在这一行
.Select(f => Assembly.LoadFile(Path.Combine(path, f.Name)))
实际上应该是
.Select(f => Assembly.LoadFrom(Path.Combine(path, f.Name)))
因为 LoadFrom 也会加载依赖项。我假设当 运行 单元测试时,依赖项必须已经加载。
程序集被进程锁定时也可能发生。 Assembly.LoadFile 和 Assmebly.LoadFrom 方法都会锁定程序集,如果您在一个进程中多次调用此方法,则可能会在第二次调用时出现此异常。
为避免锁定,您需要更改此行
.Select(f => Assembly.LoadFile(Path.Combine(path, f.Name)))
和
.Select(f => Assembly.Load(File.ReadAllBytes(Path.Combine(path, f.Name))))
如果所有依赖程序集都位于您遍历的目录中,它将起作用,否则您可以检查
System.Reflection.Assembly.LoadFile Locks File and Loading Assembly to Leave Assembly File Unlocked
我有一个 .Net4 程序集,它公开了一个抽象的基础 class。在同一个程序集中,我有一些代码反映了一个文件夹中的所有文件,以构建一个 classes 的列表,继承该基础 class。这是重要的例程
private JsonTextWriter GetAvailableServices(JsonTextWriter writer, string path)
{
try
{
writer.WriteStartArray();
writer = new DirectoryInfo(path).GetFiles(FileFilter)
.Where(f => IsAssembly(f.FullName))
.Select(f => Assembly.LoadFile(Path.Combine(path, f.Name)))
.SelectMany(a => GetLoadableTypes(a))
.Where(p => typeof(ServiceProxy).IsAssignableFrom(p) && !p.IsAbstract)
.Select(a0 => new { Instance = Activator.CreateInstance(a0), ClassName = a0.ToString() })
.Aggregate(writer, (s, v) =>
{
s.WriteStartObject();
s.WritePropertyName(ClassnameLabel);
s.WriteValue(v.ClassName);
s.WritePropertyName(DescriptionLabel);
s.WriteValue(((ServiceProxy)v.Instance).Description);
s.WriteEndObject();
return s;
});
}
catch { Exception ex; }
finally
{
writer.WriteEndArray();
}
return writer;
}
private IEnumerable<Type> GetLoadableTypes(Assembly assembly)
{
try
{
return assembly.GetTypes();
}
catch (ReflectionTypeLoadException e)
{
return e.Types.Where(t => t != null);
}
}
我有一个运行这段代码的单元测试,目标是一个特定的文件夹,它一切正常,返回一个 classes 列表,继承基础 class 作为 JSON。
以上代码位于要从 COM (VB6) 组件调用的程序集中。如果我现在从 COM 调用相同的代码,以单元测试所针对的同一文件夹为目标,我会收到反射错误,并且加载程序信息报告它无法加载包含上述代码的程序集。这只发生在 GetTypes()
调用的 GetLoadableTypes
例程中,当我反思包含 class 的程序集时,它确实继承了基础 class.
这听起来几乎像是只有在涉及 COM 时才会出现的重入问题。我想我可以将抽象基础 class 放入另一个程序集,但想知道是否还有其他事情发生。
非常感谢收到的任何解释或指示
错误信息:
ReflectionTypeLoadException "Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information."
并且在 LoaderExceptions 中:
"Could not load file or assembly 'IfxGenDocService, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.":"IfxGenDocService, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
EDIT1:我做了一些改动,将基础 class 提取到它自己的程序集中,但我仍然遇到同样的错误。也许相关的是,我有一个测试程序集,其中包含 3 个 classes 继承基础 class。我得到 3 个 LoaderExceptions(与上面报告的一样。我假设每个 class.
有 1 个问题出在这一行
.Select(f => Assembly.LoadFile(Path.Combine(path, f.Name)))
实际上应该是
.Select(f => Assembly.LoadFrom(Path.Combine(path, f.Name)))
因为 LoadFrom 也会加载依赖项。我假设当 运行 单元测试时,依赖项必须已经加载。
程序集被进程锁定时也可能发生。 Assembly.LoadFile 和 Assmebly.LoadFrom 方法都会锁定程序集,如果您在一个进程中多次调用此方法,则可能会在第二次调用时出现此异常。
为避免锁定,您需要更改此行
.Select(f => Assembly.LoadFile(Path.Combine(path, f.Name)))
和
.Select(f => Assembly.Load(File.ReadAllBytes(Path.Combine(path, f.Name))))
如果所有依赖程序集都位于您遍历的目录中,它将起作用,否则您可以检查 System.Reflection.Assembly.LoadFile Locks File and Loading Assembly to Leave Assembly File Unlocked