如何在派生类上动态调用静态方法

Posted

技术标签:

【中文标题】如何在派生类上动态调用静态方法【英文标题】:How can I dynamically call a static method on a derived class 【发布时间】:2012-11-30 16:03:08 【问题描述】:

在我的 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

按 Patient.FirstName 对访问进行排序工作正常,递归地找到该属性,但是当我尝试根据 Patient.PatientType 对访问进行排序时,找不到 PatientType 属性。 IsValidSearchProperty 最初是从查找 Patient 属性的 VisitEntity 调用的,它甚至显示为 PatientEntity 类型,但是当此方法使用 InvokeMember 递归调用自身时(这就是我尝试使用属性 Type 调用它的方式) ,在第二次调用中,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”

【问题讨论】:

你的类是如何定义的?您能否更新您的伪代码层次结构以显示它们正在使用的泛型类型?我认为这可能是问题的一部分...... 更新显示泛型 【参考方案1】:

我不知道为什么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

【讨论】:

【参考方案2】:

我自己玩了一些,想知道这可能是你的问题......

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 时会发生变化。我将尝试使其成为实例方法,因为我相信我在使用它的任何地方都实例化了对象。 我错了,我没有实例,我正在使用它,查看更新,将尝试其他建议 对不起,在第一条评论中,我的意思是在哪里调用 prop.PropertyType.InvokeMember,prop.PropertyType 是 PatientEntity,但是当调用 InvokeMember 时 GetType(T) 是 PersonEntity 我也会给你答案,你的建议是正确的,但 Kratz 把代码放在他的答案中,你有 10k 代表 :) 关键是prop.PropertyType 说的是你调用代码的对象。然而GetType(T) 没有得到你正在调用方法的类型,而是被定义为泛型参数的类型。在这种情况下,T 是在 PersonEntity 的声明中定义的,并且完全独立于层次结构。在这种情况下T 与类相同的事实是无关紧要的,它们没有任何联系。因此,当您从PersonType 派生PatientType 时,您不会更改T,因此GetType(T) 仍然是PersonEntity

以上是关于如何在派生类上动态调用静态方法的主要内容,如果未能解决你的问题,请参考以下文章

如何在南迁移期间调用 django 模型类的静态方法

继承调用其派生父方法的静态方法

派生类型的自动静态调用

C#关键字学习

派生类中的静态方法可以在 C++ 中调用受保护的构造函数吗?

spring 中AOP 功能