如何在一个派生类中动态调用静态方法?

3

在我的ASP.Net MVC页面中,我可以点击列标题按该列排序,但这涉及到aspx中的“魔法字符串”,可能会导致运行时问题。我正在尝试在运行时检查排序所传递的值是否有效。我有一个所有实体都继承自的基类:

Public MustInherit Class BaseEntity(Of T)
'Some Property and method definitions...'

    Public Shared Function IsValidSearchProperty(name As String) As Boolean
        Dim rootPart As String = name
        Dim nested As Boolean = False
        If rootPart.Contains(".") Then
            rootPart = rootPart.Split("."c)(0)
            nested = True
        End If
        Dim properties As PropertyInfo() = GetType(T).GetProperties()
        For Each prop As PropertyInfo In properties
            If prop.Name = rootPart Then
                If nested Then
                    'This is where my issue is'
                    Return Convert.ToBoolean(
                    prop.PropertyType.InvokeMember("IsValidSearchProperty",
                                                   BindingFlags.InvokeMethod Or BindingFlags.Public Or BindingFlags.Static Or BindingFlags.FlattenHierarchy,
                                                   Nothing, Nothing, New Object() {name.Substring(name.IndexOf(".") + 1)})
                                            )
                Else
                    Return True
                End If
            End If
        Next
        Return False
    End Function
End Class

这很好用,但如果我试图验证一个嵌套属性,它在类层次结构中超过1个层级。例如:

'Pseudocode Hierarchy
BaseEntity(of T)
    PersonEntity : Inherits BaseEntity(Of PersonEntity)
        Property FirstName as string
    PatientEntity : Inherits PersonEntity
        Property PatientType as int
    VisitEntity : Inherits BaseEntity(Of VisitEntity)
        Property Patient as PatientEntity

按病人名字排序的拜访记录很好,属性会被递归地找到,但当我尝试根据病人类型对拜访记录进行排序时,它无法找到PatientType属性。IsValidSearchProperty最初是从VisitEntity调用的,该实体会查找Patient属性,它甚至显示为PatientEntity类型,但当该方法使用InvokeMember递归调用自身(这就是我使用属性类型调用它的方式)时,在第二次调用中,GetType(T)的类型为PersonEntity,这个类型没有PatientType属性。有什么建议可以使嵌套调用正确解析类型?
这个方法将像这样被调用:
VisitEntity.IsValidSearchProperty("Patient.FirstName") 
VisitEntity.IsValidSearchProperty("Patient.PatientType")  '* This one doesn't work
PatientEntity.IsValidSearchProperty("PatientType")
PatientEntity.IsValidSearchProperty("FirstName")

更新

以下是我如何使用这个功能:

                Dim sorts() As String = SortExpression.Split(";")

                For Each sort As String In sorts
                    Dim sortParts() As String = sort.Split(" ")

                    If VisitEntity.IsValidSearchProperty(sortParts(0)) Then
                        If sortParts(1).ToLower = "true" Then
                            visits = visits.OrderBy(Of VisitEntity)(sortParts(0).ToString(), SortDirection.Ascending)
                        Else
                            visits = visits.OrderBy(Of VisitEntity)(sortParts(0).ToString(), SortDirection.Descending)
                        End If
                    Else
                        _log.WarnFormat("Found invalid sort property {0}", sortParts(0))
                    End If
                Next

SortExpression将类似于“Patient.PatientType True;Patient.FirstName True”

,意思是按照患者类型和名字进行排序。

你的类是如何定义的?你能否更新你的伪代码层次结构,以显示它们正在使用的通用类型?我认为这可能是问题的一部分... - Chris
更新以显示泛型。 - BlackICE
2个回答

2

我不知道为什么InvokeMember会调用基本类型而不是当前类型。但是,我会更改函数以解决该行为。下面使用了一个私有重载函数,它将要检查的类型作为参数传递。当函数深入时,它可以调用此重载函数并传递它想要检查的类型。这应该消除了方法所属的类以及GetType(T)对于该类返回的值的问题。

Public Shared Function IsValidSearchProperty(name As String) As Boolean
    Dim CurrentType = GetType(T).GetProperties()
    Return IsValidSearchProperty(name, CurrentType)
End Function 

Private Shared Function IsValidSearchProperty(name As String, CurrentType as Type) As Boolean
    Dim rootPart As String = name
    Dim nested As Boolean = False
    If rootPart.Contains(".") Then
        rootPart = rootPart.Split("."c)(0)
        nested = True
    End If
    Dim properties As PropertyInfo() = CurrentType.GetProperties()
    For Each prop As PropertyInfo In properties
        If prop.Name = rootPart Then
            If nested Then
                'This is where my issue is'
                Return IsValidSearchProperty(name.Substring(name.IndexOf(".") + 1), prop.PropertyType)

            Else
                Return True
            End If
        End If
    Next
    Return False
End Function

1

我自己也尝试了一些,想知道这是否可能是你的问题...

Sub Main
    PersonEntity.IsValidSearchProperty()
    PatientEntity.IsValidSearchProperty()
End Sub

' Define other methods and classes here

public class BaseEntity(of T)

    public shared sub IsValidSearchProperty ()
        Console.Write(GetType(T))
    end sub

end class

public class PersonEntity
    inherits BaseEntity(of PersonEntity)

end class

public class PatientEntity
    inherits PersonEntity

end class

这里是一个快速示例,展示了我认为您的继承是如何工作的。我假设在构造BaseEntity时传递的泛型参数是相关实体。我假设PersonEntity是具体的实体而不是另一个带有泛型参数的抽象实体。

我列出的代码问题在于,对于PatientEntity,在调用IsValidSearchProperty时,类型参数T仍然是从PersonEntity类继承的PersonEntity

这可能与您的类不同,但如果您的GetType返回的是PersonEntity而不是PatientEntity,则似乎这就是您的问题所在。

我假设如果您要按这些类的实例进行排序,那么您肯定有一个实例,您可以将其转换为实例方法?

或者,您可以将类型明确地传递到递归函数中,以便不是使用泛型参数上的getType,而是已经从属性的类型中确定了类型并正确地传递了它(毕竟您已经拥有该属性,因此无需努力查找其类)。

这个答案做了一些假设,但它们符合可观察到的情况,所以我希望它们是正确的并且有所帮助。如果不是,请让我知道,我会进行编辑或删除。


你已经正确地设置了层次结构。我正在更新问题以正确反映这一点。我不理解的是,在我调用GetType(T).GetProperties()的那一行中,T实际上是PatientEntity,但在下一个调用InvokeMember时,T变成了PersonEntity,因此在调用InvokeMember时发生了更改。我将尝试将其变为实例方法,因为我相信我已经在使用它的所有地方实例化了对象。 - BlackICE
我错了,在我使用它的那一点上,我没有一个实例,请查看更新,将尝试其他建议。 - BlackICE
我也可以给你答案,你的建议是正确的,但是Kratz已经在他的回答中放置了代码,而且你已经有了10k的声望 :) - BlackICE
关键是 prop.PropertyType 表示您正在调用代码的对象。但是,GetType(T) 并不是获取您调用方法的类型,而是定义为泛型参数的类型。在这种情况下,TPersonEntity 的声明中定义,并且完全独立于层次结构。在这种情况下,T 与类相同是无关紧要的,它们没有任何联系。因此,当您从 PersonType 派生 PatientType 时,不会更改 T,因此 GetType(T) 仍然是 PersonEntity - Chris
是的,谢谢Chris,我现在明白了BaseEntity(T)没有保存PatientEntity类型,因为它不是直接继承自BaseEntity,但这不是我预期的行为。 - BlackICE
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接