动态生成泛型类型失效:Get函数赋值抛出类型转换异常
解决动态创建BaSyx泛型Property时的委托类型转换异常
这个问题我之前也踩过坑,核心原因是:当你用Activator.CreateInstance创建泛型的Property(Of T)实例后,变量BasysEigenschaft的编译时类型是Object,直接给它的[Get]/[Set]属性赋值匿名函数时,VB.NET编译器会把匿名委托推断成非泛型的通用委托类型(比如VB$AnonymousDelegate_0(Of Object, Integer)),但实际上Property(Of T)的[Get]需要的是泛型的GetPropertyValueHandler(Of T)委托,两者类型不兼容,所以才会抛出InvalidCastException。
下面给你两个有效的解决方案:
方案一:通过反射匹配泛型委托类型
直接用反射获取泛型委托的类型,创建匹配的委托后再赋值给目标属性,步骤如下:
For Each Eigenschaft As PropertyInfo In Me.GetType().GetProperties() If Eigenschaft.CanRead = True Then Dim Eigenschaftstyp As Type = Eigenschaft.PropertyType ' 创建泛型Property(Of T)实例 Dim GenerischerTypBasysProperty As Type = GetType(BaSyx.Models.Core.AssetAdministrationShell.Implementations.SubmodelElementTypes.Property(Of)).MakeGenericType(Eigenschaftstyp) Dim BasysEigenschaft = Activator.CreateInstance(GenerischerTypBasysProperty) ' 设置IdShort(也可以用反射,避免编译时类型问题) GenerischerTypBasysProperty.GetProperty("IdShort").SetValue(BasysEigenschaft, Eigenschaft.Name) ' 处理Get委托:创建匹配的泛型GetPropertyValueHandler(Of T) Dim getHandlerType As Type = GetType(BaSyx.Models.Core.AssetAdministrationShell.Generics.SubmodelElementTypes.GetPropertyValueHandler(Of)).MakeGenericType(Eigenschaftstyp) Dim getDelegate As [Delegate] = [Delegate].CreateDelegate( getHandlerType, Me, Function(prop) Eigenschaft.GetValue(Me) ' 这里的逻辑和你原来的一致 ) GenerischerTypBasysProperty.GetProperty("Get").SetValue(BasysEigenschaft, getDelegate) ' 处理Set委托(仅当属性可写时) If Eigenschaft.CanWrite Then Dim setHandlerType As Type = GetType(BaSyx.Models.Core.AssetAdministrationShell.Generics.SubmodelElementTypes.SetPropertyValueHandler(Of)).MakeGenericType(Eigenschaftstyp) Dim setDelegate As [Delegate] = [Delegate].CreateDelegate( setHandlerType, Me, Sub(prop, Wert) Eigenschaft.SetValue(Me, Wert) ) GenerischerTypBasysProperty.GetProperty("Set").SetValue(BasysEigenschaft, setDelegate) End If MyBase.SubmodelElements.Add(BasysEigenschaft) End If Next
方案二:用泛型方法封装创建逻辑
这种方式更简洁,利用泛型方法的编译时类型检查来避免委托转换问题,先定义一个泛型辅助方法,再通过反射调用它:
' 定义一个私有的泛型辅助方法,专门创建匹配类型的Property(Of T) Private Function CreateBasysProperty(Of T)(propertyInfo As PropertyInfo, instance As Object) As BaSyx.Models.Core.AssetAdministrationShell.Implementations.SubmodelElementTypes.Property(Of T) Return New BaSyx.Models.Core.AssetAdministrationShell.Implementations.SubmodelElementTypes.Property(Of T)() With { .IdShort = propertyInfo.Name, .[Get] = Function(p) CType(propertyInfo.GetValue(instance), T), .[Set] = Sub(p, val) propertyInfo.SetValue(instance, val) } End Function ' 在循环中调用这个泛型方法 For Each Eigenschaft As PropertyInfo In Me.GetType().GetProperties() If Eigenschaft.CanRead = True Then ' 获取泛型方法的实例化版本(指定当前属性的类型) Dim createMethod = GetType(YourClassName).GetMethod( "CreateBasysProperty", BindingFlags.NonPublic Or BindingFlags.Instance ).MakeGenericMethod(Eigenschaft.PropertyType) ' 调用方法创建Property实例 Dim BasysEigenschaft = createMethod.Invoke(Me, New Object() {Eigenschaft, Me}) MyBase.SubmodelElements.Add(BasysEigenschaft) End If Next
注意:把代码里的YourClassName替换成你当前类的实际名称。
两种方案都能解决问题,方案二更易读和维护,推荐优先使用。
内容的提问来源于stack exchange,提问作者she
相关产品推荐
相关产品推荐

