0

次のようなクラスを宣言するとします。

Class tst
  Public Props As New Dictionary(Of String, MyProp)
End Class

これらの行に沿ってプロパティを追加しました:

Dim t As New tst
t.Props.Add("Source", new MyProp(3))

しかし、今は次のようにアクセスしたい:

t.Source

ゲッターの名前を知らずにゲッターを作成するにはどうすればよいですか?

4

1 に答える 1

1

「自動有効化」を主張する場合、そのようなことを行う唯一の方法は、コードを文字列として生成し、実行時に System.CodeDom.Compiler 名前空間のクラスを使用してコンパイルすることです。完全なクラスを最初から生成するためにしか使用したことがないため、既存のクラスにプロパティを追加する必要がある場合に機能するかどうかさえわかりませんが、拡張メソッドをコンパイルした場合はおそらく可能ですランタイム。

.NET フレームワークには、言語ごとに 1 つずつ、CodeDomeProvider クラスの複数の実装が含まれています。おそらく、Microsoft.VisualBasic.VBCodeProvider クラスに関心があるでしょう。

まず、CompilerParameters オブジェクトを作成する必要があります。その ReferencedAssemblies コレクション プロパティに、生成されたコードが参照する必要があるすべてのライブラリのリストを入力します。GenerateExecutable プロパティを False に設定します。GenerateInMemory を True に設定します。

次に、コンパイルするソース コードを含む文字列を作成する必要があります。次に、CompileAssemblyFromSource を呼び出し、CompilerParameters オブジェクトとソース コードの文字列を渡します。

CompileAssemblyFromSource メソッドは CompilerResults オブジェクトを返します。Errors コレクションには、コンパイル エラーがある場合はそのリストが含まれます。CompiledAssembly プロパティは、コンパイルされたライブラリへの参照になります (Assembly オブジェクトとして)。動的にコンパイルされたクラスのインスタンスを作成するには、CompiledAssembly.CreateInstance メソッドを呼び出します。

少量のコードを生成するだけであれば、コンパイルは非常に簡単です。ただし、コードが多い場合は、パフォーマンスへの影響に気付く場合があります。

単一の動的プロパティを含む動的クラスを生成する方法の簡単な例を次に示します。

Option Strict Off

Imports System.CodeDom.Compiler
Imports Microsoft.VisualBasic
Imports System.Text

Public Class Form3
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim code As StringBuilder = New StringBuilder()
        code.AppendLine("Namespace MyDynamicNamespace")
        code.AppendLine("   Public Class MyDynamicClass")
        code.AppendLine("       Public ReadOnly Property WelcomeMessage() As String")
        code.AppendLine("           Get")
        code.AppendLine("               Return ""Hello World""")
        code.AppendLine("           End Get")
        code.AppendLine("       End Property")
        code.AppendLine("   End Class")
        code.AppendLine("End Namespace")
        Dim myDynamicObject As Object = generateObject(code.ToString(), "MyDynamicNamespace.MyDynamicClass")
        MessageBox.Show(myDynamicObject.WelcomeMessage)
    End Sub


    Private Function generateObject(ByVal code As String, ByVal typeName As String) As Object
        Dim parameters As CompilerParameters = New CompilerParameters()
        parameters.ReferencedAssemblies.Add("System.dll")
        parameters.GenerateInMemory = True
        parameters.GenerateExecutable = False
        Dim provider As VBCodeProvider = New VBCodeProvider()
        Dim results As CompilerResults = provider.CompileAssemblyFromSource(parameters, code)
        If results.Errors.HasErrors Then
            Throw New Exception("Failed to compile dynamic class")
        End If
        Return results.CompiledAssembly.CreateInstance(typeName)
    End Function
End Class

注意してください、私は決して を使用Option Strict Offしませんが、この例では簡単にするためにオフにして、myDynamicObject.WelcomeMessageすべてのリフレクション コードを自分で書かなくても簡単に呼び出すことができるようにしました。

リフレクションを使用してオブジェクトのメソッドを呼び出すことは、苦痛で危険な場合があります。したがって、生成されたアセンブリと、生成されたアセンブリを呼び出す固定アセンブリの両方によって参照される共有アセンブリに基本クラスまたはインターフェイスを提供すると役立つ場合があります。これにより、動的に生成されたオブジェクトを厳密に型指定されたインターフェイスを介して使用できます。

あなたの質問に基づいて、あなたはJavaScriptのような動的言語に慣れているだけで、間違った考え方を使用して解決策を考えているだけであり、実際にこのようにする必要がある、またはそうすべきではない. ただし、.NET でこれを行う方法を知っておくと、状況によっては確実に役立ちます。定期的にやりたいことではないことは間違いありませんが、カスタム スクリプトをサポートして複雑な検証やデータ変換を実行する必要がある場合は、このようなものが非常に役立ちます。

于 2012-05-12T23:52:58.297 に答える