C#通过反射将派生类转换为基类异常
Posted
技术标签:
【中文标题】C#通过反射将派生类转换为基类异常【英文标题】:C# cast derived class to base class exception via reflection 【发布时间】:2016-05-24 17:30:06 【问题描述】:我有一个使用反射动态创建类的应用程序。部署后,将派生类转换为其基类时出现异常。它只发生在 100 台机器中的 1 台上。所有的类都在同一个程序集中。下面是一些代码 sn-ps 和在强制转换异常之前从日志消息中输出。我无能为力,非常感谢任何帮助。
//Parent class
namespace Framework.DataModel
[Serializable]
public class DataTreeRequest : TreeNode, IDirtyListener, ISerializable
....
// Derived Class
namespace Framework.DataModel
[Serializable]
public class CADElementRequest : DataTreeRequest
public CADElementRequest(String name) : base(name)
// Method that uses reflection to create class and then cast to its base class
namespace Framework.DataModel
[Serializable]
public class DataModelBuilder : CoreBuilder
...
protected DataTreeRequest CreateDataTreeRequest(String asmName, String inName, String inType, String inSourceName)
DataTreeRequest dtr = null;
Assembly asm = Assembly.LoadFrom(asmName);
if (asm == null)
throw new BaseException("Can't find assembly " + asmName);
Type requestType = asm.GetType(inType);
if (requestType == null)
throw new BaseException("Can't find class of type " + inType + " in assembly " + asmName);
// Call the constructor for the tree node that takes the xml node as an argument
Type[] constructorArgsTypes = new Type[1];
constructorArgsTypes[0] = typeof(String);
ConstructorInfo constructorInfo = requestType.GetConstructor(constructorArgsTypes);
if (constructorInfo == null)
throw new BaseException("Can't find constructor for type " + inType + " that takes a String param");
Object[] constructorArgs = new Object[1];
constructorArgs[0] = inName;
Object newObj = constructorInfo.Invoke(constructorArgs);
// Code fails on this line trying to cast derived class to base class on 1 in 100 machines
dtr = newObj as DataTreeRequest;
if (dtr == null)
throw new BaseException("Can't cast newObj to type DataTreeRequest. newObj = " + newObj + ", Type = " + newObj.GetType().ToString());
dtr.InSource = inSourceName;
return dtr;
故障机器上的日志输出:
消息=找到程序集=Framework.DataModel,版本=1.0.5885.31486, Culture=neutral, PublicKeyToken=null
消息 = newObj AssemblyQualifiedName=Framework.DataModel.CADElementRequest, Framework.DataModel,版本=1.0.5885.31486,文化=中性, PublicKeyToken=null,BaseType==Framework.DataModel.DataTreeRequest, FullName==Framework.DataModel.CADElementRequest
BaseException:无法将 newObj 转换为类型 DataTreeRequest。新对象 = Name=Substations;InType=;InName=Substations;OutName=Substations;InSource=;OutSource=;, 类型 = Framework.DataModel.CADElementRequest
【问题讨论】:
为newObj.GetType().BaseClass == typeof(DataTreeRequest)
添加一个断言。应该开火。此外,为所涉及的完全限定类型名称添加日志记录。同一个程序集可能有多个版本吗?可能是部署错误?
已经在错误信息“BaseType==Framework.DataModel.DataTreeRequest”上
@CodeNotFound 这只是类型名称,缺少程序集。
也许可以尝试为Type.IsAssignableFrom 添加检查并在Type.Module 等异常中添加更多日志记录/详细信息
我尝试测试 newObj.GetType().BaseClass == typeof(DataTreeRequest) 确实是错误的。我还尝试使用与创建 CADElementRequest 时相同的样式代码来创建 DataTreeRequest 父对象。工作正常。组装版本是相同的。该应用程序使用 App-V 部署在带有 GUID 等的超长目录路径中。 .NET 中是否有完整的路径长度限制?
【参考方案1】:
尝试替换
Assembly asm = Assembly.LoadFrom(asmName);
if (asm == null)
throw new BaseException("Can't find assembly " + asmName);
Type requestType = asm.GetType(inType);
与
Type requestType = Type.GetType(inType)
其中 inType 是程序集限定名 https://msdn.microsoft.com/en-us/library/system.type.assemblyqualifiedname(v=vs.110).aspx
如果您需要加载项目未引用的程序集,请考虑使用 Assembly.Load 方法。
关于使用 Assembly.LoadFrom 的缺点请阅读 https://msdn.microsoft.com/EN-US/library/1009fa28(v=VS.110,d=hv.2).aspx 中的备注部分
【讨论】:
【参考方案2】:危险信号是它在特定机器上失败(100 台机器中的 1 台) - 代码总共在多少台机器上失败?这表明它可能是机器的配置而不是代码。这也使得复制以提供帮助变得极其困难。
如果是我。我会退后一步,简化情况。编写只执行失败任务的代码,即使使用其他更简单的类,然后专注于失败的机器。尽可能多地获取信息并建立理解。
这很可能是指涉性疼痛。你所面临的情况只是真正问题的表象。您专注于代码,但这只是一个症状。这就是简化的原因。
希望这会有所帮助,我是 *** 的新手,我知道有问题需要遵循的规则。我会对此发表评论,但我没有这方面的声誉。
【讨论】:
以上是关于C#通过反射将派生类转换为基类异常的主要内容,如果未能解决你的问题,请参考以下文章