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#通过反射将派生类转换为基类异常的主要内容,如果未能解决你的问题,请参考以下文章

将派生类转换为基类

将指针从派生类转换为基类的最佳方法

无法将参数 1 从派生指针转换为基类指针引用

Part7 继承与派生 7.3基类与派生类类型转换

如何将此“命令处理程序映射”从派生类重构为基类?

C ++:将void *转换为基类指针时访问冲突