あなたが "auto-vivifying"を主張するならば、私が知っている唯一の方法は、コードを文字列として生成し、それを実行時にSystem.CodeDomのクラスを使ってコンパイルすることです.Compiler名前空間。私は最初から完全なクラスを生成するためにこれまでに使ったことがあるので、既存のクラスにプロパティを追加する必要がある場合でも機能するかどうかはわかりませんが、ランタイム。
.NET Frameworkには、言語ごとに1つ、CodeDomeProviderクラスの複数の実装が含まれています。 Microsoft.VisualBasic.VBCodeProviderクラスに興味があります。
まず、CompilerParametersオブジェクトを作成する必要があります。そのReferencedAssembliesコレクションプロパティに、生成されたコードが参照する必要があるすべてのライブラリのリストを入力します。 GenerateExecutableプロパティをFalseに設定します。 GenerateInMemoryをTrueに設定します。
次に、コンパイルするソースコードを含む文字列を作成する必要があります。次に、CompileAssemblyFromSourceを呼び出し、CompilerParametersオブジェクトとソースコードの文字列を渡します。
CompileAssemblyFromSourceメソッドは、CompilerResultsオブジェクトを返します。 Errorsコレクションにはコンパイルエラーのリストが含まれています(存在する場合)。CompiledAssemblyプロパティは、(アセンブリオブジェクトとしての)コンパイル済みライブラリへの参照になります。動的にコンパイルされたクラスのインスタンスを作成するには、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でこれを行う方法を知ることは、いくつかの状況では間違いなく便利です。定期的にやりたいことではありませんが、複雑な検証やデータ変換を実行するカスタムスクリプトをサポートする必要がある場合は、このようなものが非常に便利です。
名前を知らないと、ゲッターの使い方を説明してください。あなたは理由があると確信しています。それが何であれ、問題を理解するのに役立ちます。 –
私は必要なものを表現する方法がわかりませんでした。基本的には最後の文を無視し、実際に 'Source'プロパティを宣言しなくても' t.Source'参照を許可する解決策に集中します。その理由は、実行時にプロパティが作成されるということです。 – ekkis
実行時に作成されるプロパティは何ですか?それがコンパイルされていない場合は、リフレクションを経ることを除いて、消費者は使用できなくなります。 –