我试图遍历类中的对象(字段)并在每个对象上调用一个方法。每个对象都是不同的类型。这是父类:
Public Class MySettings
Public IdentifyByFacType As RadioButtonSetting
Public WtrFacTypes As ListSetting
Public OilFacTypes As ListSetting
Public GroupByRef As CheckboxSetting
Public GroupRefAttr As TxtboxSetting
End Class
以下是其中一个子对象类的一部分:
<Serializable>
Public Class TxtboxSetting
<XmlIgnore()>
Public MyControl As Windows.Forms.TextBox
<XmlIgnore()>
Public DefaultSetting As String
Private _SavedSetting As String
Public Property SavedSetting As String
Get
Return _SavedSetting
End Get
Set(value As String)
_SavedSetting = value
CurrentValue = value
End Set
End Property
Public Sub New()
End Sub
Public Sub New(DefaultSetting As String, MyControl As Windows.Forms.TextBox)
Me.DefaultSetting = DefaultSetting
Me.MyControl = MyControl
End Sub
Public Sub RestoreDefault()
CurrentValue = DefaultSetting
End Sub
End Class
MySettings
类的所有子对象(例如GroupRefAttr
)具有相同的方法和属性,但内部代码不同。
所以我将有几个类,如MySettings
类,每个类都有不同的子对象。给定这样一个类的实例,我想自动遍历字段并在每个字段上调用方法RestoreDefault
。我不想知道MySettings
课程中存在哪些对象。相反,知道他们都有RestoreDefault
方法,我只想在每个对象上调用方法。
尽管经常进行搜索,我还没有办法做到这一点。通过反思,我只能做到这一点:
Dim Opts as New MySettings
For Each var In Opts.GetType.GetFields
Dim RestoreDefault As System.Reflection.MethodInfo = var.FieldType.GetMethod("RestoreDefault")
RestoreDefault.Invoke(Opts, Nothing)
Next
但是,在RestoreDefault.Invoke(Opts, Nothing)
行中,我无法传递Opts
,因为我正在处理Opts
中的字段,而不是Opts
本身。像这样的语句可以起作用:RestoreDefault.Invoke(Opts.GroupRefAttr, Nothing)
,但是这需要我提前知道MySettings
类中的对象,这会破坏目的。有没有办法在运行时抓取字段实例对象并将其关闭?
答案 0 :(得分:0)
当你调用RestoreDefault
方法时,你需要在设置(即字段的值)上调用它,而不是包含设置的类。将代码更改为此可以解决您的问题:
Dim Opts as New MySettings
For Each var In Opts.GetType.GetFields
Dim setting As Object = var.GetValue(Opts)
Dim RestoreDefault As System.Reflection.MethodInfo = var.FieldType.GetMethod("RestoreDefault")
RestoreDefault.Invoke(setting, Nothing)
Next
但是,如果您引入基类或接口,您应该能够摆脱部分或全部反射。容器设置类可以具有一组设置,每个设置都具有共享基类或具有RestoreDefault
方法的接口。然后,容器设置类将通过基类或接口调用此方法,而不必使用反射。
基类:
Public MustInherit Class BaseSetting
Public MustOverride Sub RestoreDefault
End Class
特定设置类:
Public Class TxtboxSetting
Inherits BaseSetting
Public Overrides Sub RestoreDefault()
' Specific implementation
End Sub
End Class
在源自BaseSetting
的任何类中,您现在可以调用RestoreDefault
方法而无需使用反射。
但是,考虑到您的设计,您可能仍希望使用反射来获取MySettings
类中的设置。你可以这样做:
Dim settings = From fieldInfo in Opts.GetType.GetFields
Where GetType(BaseSetting).IsAssignableFrom(fieldInfo.FieldType)
Select DirectCast(fieldInfo.GetValue(Opts), BaseSetting)
For Each setting In settings
setting.RestoreDefault()
Next
反射用于查找从BaseSetting
派生的所有字段,然后在每个字段上调用RestoreDefault
。这种方法不会受到&#34;魔术字符串&#34;代码取决于字符串中表示的RestoreDefault
方法的名称的问题。
(另外,调用MySettings
类父有点误导,因为没有从MySettings
继承。而是这个类包含其他设置。)
答案 1 :(得分:0)
MySettings类的所有子对象(例如GroupRefAttr)具有相同的方法和属性,但内部代码不同。
在这种情况下,应定义子对象类型,使它们实现一个需要存在相同方法和属性的公共接口。现在,我将命名该接口IControlSetting
。然后,您的For
循环看起来像这样:
Dim Opts as New MySettings
For Each var In Opts.GetType.GetFields
Dim setting As IControlSetting = TryCast(var.GetValue(Opts), IControlSetting)
If setting Is Nothing Then Continue
setting.RestoreDefault()
Next
此外,我还要更改您的MySettings
类型以封装字典或IControlSetting
对象。然后你可以迭代字典来检查每个对象,而不是需要反射。这可能是这样的:
Public Class MySettings
Private allSettings As Dictionary(Of String, IControlSetting)
Public Sub New()
allSettings = new Dictionary(Of String, IControlSetting)()
allSettings.Add("IdentifyByFacType", New RadioButtonSetting())
allSettings.Add("WtrFacTypes", New ListSetting())
allSettings.Add("OilFacTypes", New ListSetting())
'...
End Sub
Public Property IdentifyByFacType As RadioButtonSetting
Get
Return DirectCast(allSettings("IdentifyByFacType"), RadioButtonSetting)
End Get
'The setters may be optional, depending on how you expect to use these
Set(ByVal value As RadioButtonSetting)
allSettings("IdentifyByFacType") = value
End Set
End Property
Public Property WtrFacTypes As ListSetting
Get
Return DirectCast(allSettings("WtrFacTypes"), RadioButtonSetting)
End Get
Set(ByVal value As ListSetting)
allSettings("WtrFacTypes") = value
End Set
End Property
Public Property OilFacTypes As ListSetting
Get
Return DirectCast(allSettings("OilFacTypes"), RadioButtonSetting)
End Get
Set(ByVal value As ListSetting)
allSettings("OilFacTypes") = value
End Set
End Property
'...
Public Sub RestoreAllDefaults()
For Each setting As KeyValuePair(Of String, IControlSetting) In allSettings
setting.Value.RestoreDefault()
Next setting
End Sub
End Class