我正在开发一个 C# 应用程序,该应用程序应该检查其他 C# 可执行文件,并通过单元测试断言有关它们公开的接口(interface)的某些属性。 (就上下文而言,这是一个 CS 类(class)的评分应用程序;作业是从文本文件中解析数字范围并根据固定接口(interface)返回它们。)
到目前为止,我已经做到了:
- 将可执行文件加载为变量
assembly
,使用Assembly.LoadFrom(string)
- 使用
assembly.GetType(string)
获取相关接口(interface)的类型 - 再次使用
assembly.getType(string)
查找接口(interface)的实现类型 - 将实现类型实例化为
dynamic
对象,使用type.GetConstructor(Type[])
和constructor.Invoke(Object[])
此时,我有一个 dynamic
对象loader
我知道实现了我正在测试的接口(interface)。我想调用 obj
上的接口(interface)方法之一,所以我运行:
dynamic rangeSet = loader.GetRangeSetFromFile (inputFile); // inputFile is a string
这会抛出 InvalidCastException
具有以下跟踪:
System.InvalidCastException : Cannot cast from source type to destination type.
at SwapAssignment3.Implementations.RangeLoaderAdapter.GetRangeSetFromFile (string) <IL 0x0001e, 0x00066>
at (wrapper dynamic-method) object.CallSite.Target (System.Runtime.CompilerServices.Closure,System.Runtime.CompilerServices.CallSite,object,string) <IL 0x00036, 0x0007b>
at System.Dynamic.UpdateDelegates.UpdateAndExecute2<object, string, object> (System.Runtime.CompilerServices.CallSite,object,string) <0x003cf>
at AssignmentTests.R3Test.TestLoadingViaInterface () [0x00054] in /Users/tim/Dropbox/Courses/CSSE375-TA/AssignmentTests/AssignmentTests/R3Test.cs:82
at (wrapper managed-to-native) System.Reflection.MonoMethod.InternalInvoke (System.Reflection.MonoMethod,object,object[],System.Exception&) <0x00003>
at System.Reflection.MonoMethod.Invoke (object,System.Reflection.BindingFlags,System.Reflection.Binder,object[],System.Globalization.CultureInfo) <IL 0x000db, 0x00147>
为什么会抛出这个错误?运行有问题的可执行文件本身就可以正常工作;此错误仅在我的测试应用程序的上下文中抛出。正文GetRangeSetFromFile
方法如下:
public IRangeSet GetRangeSetFromFile(string filePath)
{
var newRange = new RangeStorage();
_fileProcessor.ProcessFile(filePath);
newRange.StoreElements((List<IRange>) _fileProcessor.GetStorage());
return newRange;
}
我有充分的理由相信(从程序输出等),强制转换错误是从第三行引发的,List<IRange>
throw ;然而,由于跟踪给出了 IL 位置,所以我不能 100% 确定这一点,而且我不知道为什么该转换首先会失败,因为如果程序单独运行(在我的外部),它就可以正常工作。测试员)。
我的主要问题是:为什么会引发此转换错误,以及如何避免它?
编辑:根据请求,测试代码如下:
Type interfaceType = assembly.GetType("IRangeLoader");
List<Type> implementingTypes = new List<Type> (assembly.GetTypes ())
.FindAll ((Type t) => t.IsClass)
.FindAll ((Type t) => (new List<Type> (t.GetInterfaces ())).Contains (interfaceType));
Type implementingType = implementingTypes[0];
ConstructorInfo ctor = implementationType.GetConstructor (new Type[] {});
dynamic loader = ctor.Invoke (new Object[] {});
dynamic rangeSet = loader.GetRangeSetFromFile ("sample range.txt");
最佳答案
好的,下面的代码似乎可以在另一个程序集中调用该方法:
Assembly testAssembly = Assembly.LoadFile(<path>);
var interfaceType = testAssembly.GetTypes().Where(x => x.Name == "ISampleInterface").FirstOrDefault();
if(interfaceType != null)
{
var implementingType = testAssembly.GetTypes().Where(typ => type.GetInterfaces().Any(iface => iface == interfaceType)).FirstOrDefault();
if(implementingType != null)
{
dynamic obj = Activator.CreateInstance(implementingType);
dynamic result = obj.SampleInterfaceMethod();
Console.WriteLine(result);
}
}
尝试使用其中的一些。我能够调用该对象,然后从该方法获取结果。
关于C#:反射实例化对象会引发转换错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10436274/