【问题标题】:.net dynamic loading.net 动态加载
【发布时间】:2011-06-04 09:42:18
【问题描述】:

我已经看到其他一些关于此的回复,他们谈论接口,但我很确定您可以使用类和基类来做到这一点,但我不能这样做。

Public Class Behavior
Private _name As String
Public ReadOnly Property Name As String
    Get
        Return _name
    End Get
End Property

Public Property EditorUpdate As Boolean

Public Sub New(ByVal name As String)
    _name = name
    EditorUpdate = False
End Sub

Public Overridable Sub Update()

End Sub

' runs right away in editor mode. also runs when in stand alone game mode right away
Public Overridable Sub Start()

End Sub

' runs after game mode is done and right before back in editor mode
Public Overridable Sub Finish()

End Sub

' runs right when put into game mode
Public Overridable Sub Initialize()

End Sub

' runs when the game is complete in stand alone mode to clean up
Public Overridable Sub Destroy()

End Sub

结束类

Public Class CharacterController
Inherits Behavior.Behavior

Public Sub New()
    MyBase.New("Character Controller")

End Sub

Public Overrides Sub Update()
    ' TODO: call UpdateController()
    ' THINK: how can UpdateController() get the controller entity it's attached to?
    ' Behaviors need a way to get the entity they are attached to. Have that set when it's assigned in the ctor?
End Sub

结束类

Dim plugins() As String
    Dim asm As Assembly


    plugins = Directory.GetFileSystemEntries(Path.Combine(Application.StartupPath, "Plugins"), "*.dll")

    For i As Integer = 0 To plugins.Length - 1
        asm = Assembly.LoadFrom(plugins(i))

        For Each t As Type In asm.GetTypes
            If t.IsPublic Then
                If t.BaseType.Name = "Behavior" Then
                    behaviorTypes.Add(t.Name, t)


                    Dim b As Behavior.Behavior
                    b = CType(Activator.CreateInstance(t), Behavior.Behavior)
                    'Dim o As Object = Activator.CreateInstance(t)


                End If
            End If
        Next
    Next

当它尝试将 Activator.CreateInstance(t) 返回的任何内容转换为 Behavior 类型的基类时,我得到了无效的强制转换异常。该类型应该是 CharacterController ,它被定义为 Behavior 的子级,那么为什么不让我转换它呢?我以前做过类似的事情,但我找不到我的代码。我错过了什么?

【问题讨论】:

  • 也许用DirectCast(Activator.CreateInstance(t), Behavior)
  • 是的,我都试过了,但还是不行。 ://
  • 也许你应该检查返回的对象的类型,看看它到底是什么。
  • 它说 CharacterController.CharacterController。它说它的基本类型是 Behavior.Behavior。这就是让我困惑的地方。此外,如果我专门引入 CharacterController 的引用并创建它的一个对象,那么一切正常。所以我一定是错过了什么。

标签: vb.net reflection dynamic


【解决方案1】:

这可能不是您问题的答案(它也可能解决您的异常——谁知道呢),但这是需要指出的。这些行:

If t.IsPublic Then
    If t.BaseType.Name = "Behavior" Then

真的应该改成这样一个条件:

If t.IsPublic AndAlso (Not t.IsAbstract) AndAlso _
    GetType(Behavior.Behavior).IsAssignableFrom(t) Then

否则,如果有人在他们自己的程序集中定义了一个名为“行为”的随机类型,并从另一种类型派生出来,你的代码会认为它是一个插件。此外,如果有人派生了您的 Behavior 类型,然后派生了该类型(两个继承级别),则此代码将错误地跳过该类型。使用IsAssignableFrom 方法是一种快速简便的方法,可以确保一个类型确实派生自您想要的特定类型(而不是任何具有相同名称的类型),即使您的类型之间存在另一种类型。继承树。针对t.IsAbstract 的额外检查也将确保您不会尝试实例化基本插件类型的抽象子类型。

【讨论】:

  • 酷,我会使用上面的。我不喜欢嵌套命名空间,但老实说,在这种情况下,每个 dll 有 1 个类,并且为了给项目一个有意义的名称,我只是将项目创建为任何类。当然,命名空间也是这样命名的。我意识到我可以改变它,但我从来不知道要改变什么。它似乎让我做 Behavior.Behavior 就好了?
  • @user441521:嗯,我认为这是 CIL 级别的限制,但也许这只是 C# 中的限制。
  • 这很有趣。我把它放进去,它现在没有通过 if 检查!这可以解释为什么它会给出错误,但现在仍然可以确定我错过了什么。
  • 您可以在调试器中启动它并查看哪个测试失败。很明显,您看到的“行为”超类型与您认为的类型不同。如果加载了相同程序集(但不同版本)的两个副本,则可能会发生这种情况,因为您引用的行为类型位于不同的程序集中(因此不是同一类型)。但这是一个非常难以实现的情况,所以可能不是这样。为了安全起见,请重建所有内容并确保 GAC 中没有任何程序集的副本。
【解决方案2】:

这对我有用:

             Dim ctor As Reflection.ConstructorInfo = _
                t.GetConstructor(New System.Type() {})
             Dim o As Object = ctor.Invoke(New Object() {})
             Dim plugin As Plugin = TryCast(o, Plugin)

(如果找到t,我调用无参数构造函数。)

[我刚刚意识到这可能是 Activator.CreateInstance 所做的,所以我用你的代码替换了我的代码,它按照你的方式工作——所以这可能对你没有帮助]

【讨论】:

    猜你喜欢
    • 2011-01-22
    • 1970-01-01
    • 2010-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多