2012-05-12 17 views
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 

どのようにすることができます私はゲッターの名前を知らずにゲッターを作成しますか?

+0

名前を知らないと、ゲッターの使い方を説明してください。あなたは理由があると確信しています。それが何であれ、問題を理解するのに役立ちます。 –

+0

私は必要なものを表現する方法がわかりませんでした。基本的には最後の文を無視し、実際に 'Source'プロパティを宣言しなくても' t.Source'参照を許可する解決策に集中します。その理由は、実行時にプロパティが作成されるということです。 – ekkis

+1

実行時に作成されるプロパティは何ですか?それがコンパイルされていない場合は、リフレクションを経ることを除いて、消費者は使用できなくなります。 –

答えて

1

あなたが "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でこれを行う方法を知ることは、いくつかの状況では間違いなく便利です。定期的にやりたいことではありませんが、複雑な検証やデータ変換を実行するカスタムスクリプトをサポートする必要がある場合は、このようなものが非常に便利です。

+1

私は、私はVisualStudioにアクセスして何かを書いて、月曜日までテストしていません。私がするとき、簡単な例を示すために私の答えを編集します。 –

+0

私は笑っている...これは私が想像していたよりはるかに複雑です。私はあなたの回答を答えとしてタグ付けしています。あなたが提供するコードを使用している可能性は低いですが、それを投稿するのは良いアイデアでしょう。実際に、私はそれがちょうど時間の問題であることを確信しています。私はこのような贅沢を味わう他のシナリオに踏み込んでいます。ありがとうございました。 – ekkis

+0

@ekkis私は自分の答えを更新し、サンプルコードと説明を追加しました。 –

関連する問題