2008年5月10日土曜日

文字列指定したクラスのインスタンス作成

のメモ。
// namespaceを取得
String ns = this.GetType().Namespace;

// ClassAのTypeを取得
Type type = Type.GetType(String.Format("{0}.{1}", ns, "ClassA"), false);

// ClassAのインスタンス作成
ClassA a = Activator.CreateInstance(type) as ClassA;
↑は既にクラスを定義してあり、アセンブリも読み込んでいる必要があるが、 文字列から動的にクラス自体を作ることも出来る。
プログラムからソース・コードをコンパイルして実行するには?
必要な部分だけ抜粋しておく。
using System;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.Reflection;

public class CompileInvoke {
  static string cs = @"
    public class CSHello {
      public static void Main() {
        System.Console.WriteLine(""Hello C# World!"");
      }
    }";

  public static void Main() {
    CSharpCodeProvider cscp = new CSharpCodeProvider();
    ICodeCompiler cc = cscp.CreateCompiler();

    CompilerParameters param = new CompilerParameters();
    param.GenerateInMemory = true;

    CompilerResults cr = cc.CompileAssemblyFromSource(param, cs);
    Assembly asm = cr.CompiledAssembly;

    Type type = asm.GetType("CSHello");

    MethodInfo mi = type.GetMethod("Main");
    mi.Invoke(null, null);  // 出力:Hello C# World!"
  }
}

2008年5月6日火曜日

DynamicSilverlightをVisualStudioで開発してみる

前回のHTMLをエスケープするSilverlightアプリをIronRubyで実装してみる。 この開発だけならVisualStudioを使わなくてもできるのだが、今回はASP.NET MVCとの組み合わせで実装してみようと思うのでVSを使用。ここ Dynamic Silverlight Part 3: Integrating Silverlight with ASP.NET MVCを参考にしている。 ただ、今回のアプリはMVCである必要は全く無い。
ソースはここに置いた。
  1. 準備

  2. 必要なものはこの辺 ASP.NET 3.5 Extensions Preview を見て揃えておく。 あと、今回はDynamic SilverlightなのでDynamic Silverlight SDKはここDynamic Silverlightからダウンロードしたものを使用する(こっちのほうが最新)。
  3. ASP.NET MVCプロジェクトを作成

  4. HtmlEscapeDslという名前でASP.NET MVCプロジェクトを作成する。 作成直後のフォルダ構成。
  5. プロジェクトプロパティの設定

  6. まずはBuild EventsタブでPost-build eventを設定。ここでXAPファイルを作成するように設定。ただしChiron.exeのパスは通しておく必要がある。 次にWebタブでSilverlightをデバッグできるようにする。
  7. Silverlightアプリを表示する

  8. 表示はobjectタグで設定すればどこでも出来るのだが今回はSite.Masterに共通部分であるJavascriptとCSSの設定をして、Indexにobjectタグを設定する。 この状態でコンパイルして表示すると↓のようになる。まだ表示するXAPファイルが無いのでエラーになっている。
  9. App、Assetsフォルダとファイルの配置

  10. プロジェクトにAppフォルダとAssetsフォルダを追加する。AssetsフォルダにはCSSを追加。 Appフォルダには必要なDLLを入れておく(XAPファイル作成の際に組み込んでくれる)。 今回はIronPythonは使用しないので不要だが取り敢えず入れておく。
  11. AppManifest.xamlの設定

  12. AppManifest.xamlの作成は、
    Chiron /m /d:App
    
    で作成されるが、これだとDynamicSilverlight関係のアセンブリが読み込まれないので以下のように手動でAppManifest.xamlを設定する。
    <Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" RuntimeVersion="2.0.30226.00" EntryPointAssembly="Microsoft.Scripting.Silverlight" EntryPointType="Microsoft.Scripting.Silverlight.DynamicApplication">
      <Deployment.Parts>
        <!-- Core DLR and DLR <-> Silverlight shim assemblies -->
        <AssemblyPart Name="Microsoft.Scripting.Silverlight" Source="Microsoft.Scripting.Silverlight.dll" />
        <AssemblyPart Source="Microsoft.Scripting.dll" />
        
        <!-- Language assemblies -->
        <AssemblyPart Source="IronRuby.dll" />
        <AssemblyPart Source="IronRuby.Libraries.dll" />
        <AssemblyPart Source="IronPython.dll" />
        <AssemblyPart Source="IronPython.Modules.dll" />
        
        <!-- Silverlight Controls -->
        <AssemblyPart x:Name="System.Windows.Controls.Data" Source="System.Windows.Controls.Data.dll" />
        <AssemblyPart x:Name="System.Windows.Controls" Source="System.Windows.Controls.dll" />
        <AssemblyPart x:Name="System.Windows.Controls.Extended" Source="System.Windows.Controls.Extended.dll" />
      </Deployment.Parts>
    </Deployment>
    
    下部のSilverlight Controlsを読み込むことでButtonやTextBoxが使用できるようになる。
  13. App.xaml

  14. 以前作成したC#版とほとんど同じで大丈夫だがイベントハンドラ部分は削除する必要がある。イベントハンドラはapp.rbで登録と実装を行う。さらにx:Classも変更する(UserControlを継承したクラスを指定することは出来ないみたい。たぶんこの辺はSilverlight2正式版では開発できるようになると思うんだけどなぁ。そうじゃないと今のところ独自コントロールを読み込む手段がないし)。あと、これは必須ではないが名前もRubyの変数で一般的に使う形式に変更した方がいいかも。 全く同じだと面白くないので入力はWatermarkedTextBoxを使用するようにした。
    <UserControl x:Class="System.Windows.Controls.UserControl"
        xmlns="http://schemas.microsoft.com/client/2007"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Width="400" Height="300"
        >
      
      <Grid x:Name="layout_root" Background="#FFBDD6DF">
        <Grid.RowDefinitions>
          <RowDefinition Height="0.4*"/>
          <RowDefinition Height="0.127*"/>
          <RowDefinition Height="0.473*"/>
        </Grid.RowDefinitions>
        <Canvas HorizontalAlignment="Stretch" Margin="8,8,8,8" VerticalAlignment="Stretch">
          <WatermarkedTextBox Width="384" Height="104" x:Name="wtb_input" Watermark="Input..." AcceptsReturn="True"/>
        </Canvas>
        <Button HorizontalAlignment="Center" Margin="173,8,167,11.1000003814697" VerticalAlignment="Stretch" Grid.Row="1" Content="変換" x:Name="btn_convert"/>
        <Canvas HorizontalAlignment="Stretch" Margin="8,8,8,8" VerticalAlignment="Stretch" Grid.Row="2">
          <TextBox Width="384" Height="127" x:Name="txb_output" IsReadOnly="True"/>
        </Canvas>
        <Button HorizontalAlignment="Right" Margin="0,8,8,11.1000003814697" VerticalAlignment="Stretch" Width="60" Grid.Row="1" Content="クリア" x:Name="btn_clear"/>
      </Grid>
    </UserControl>
    
  15. app.rb

  16. イベントハンドラを登録。ほとんどのことをSilverlightApplicationクラスがやってくれるのでコード量はかなり少ない。
    System.Windows.BrowserのHttpUtilityもそのまま使えるのでHTMLエスケープ変換のコードもC#版そのままでOK。
    require "silverlight"
      
    class App < SilverlightApplication
      use_xaml
      
      def initialize
        btn_convert.click do |s, a|
          txb_output.text =  HttpUtility.html_encode(wtb_input.text)
        end
        
        btn_clear.click do |s, a|
          wtb_input.text = ""
          txb_output.text = ""
        end
      end
    end
      
    App.new
    
  17. 表示してみる

  18. やっぱり日本語が入力できないぞ・・・。しかも今度はローカルでも入力できない。何か設定が必要なのかな。
  19. デバッグも大丈夫

  20. app.rb内のボタンクリックにブレークポイントを実行したところ。一応止まるしローカル変数の値も見られるが、F11でステップインは出来ない。Silverlight2正式版の時にはRubyのIntellisenseも動くようにしてほしいなぁ。