F#で.NET Remotingしてみる。
この記事のサンプルコードとほぼ同じことをしよう。まずはリモートオブジェクトのクラスを定義するソース(obj.fs)から。
module RemoteTest
open System
type MyRemoteObject =
class
inherit MarshalByRefObject
val hole : unit
new () =
{
inherit MarshalByRefObject();
hole = Console.WriteLine("Constructor called.")
}
override x.Finalize() = Console.WriteLine("Destructor called.")
member x.sayHello s = "Hello, " ^ s ^ "!"
end
解説しよう。holeというunit型変数は、コンストラクタ中で手続きを実行するための非常手段だ。正しいやり方があるのかもしれないが、見つけられなかった。F#自体にはデストラクタの構文がないので、Finalize()をオーバーライドしている。正しく動くかどうかは自信がない。
リモートオブジェクトは.NETアセンブリとしてpublicなクラスでなければならない。F#が作る.NETアセンブリのクラスをpublicにするには、インターフェイスファイル(拡張子fsi)が要る。
module RemoteTest
open System
type MyRemoteObject =
class
inherit MarshalByRefObject
new : unit->MyRemoteObject
member sayHello : string -> string
end
本当にこれでいいのか知らないが、とりあえず現在のコンパイラ(バージョン1.1.8.1)ではこれで動く。
Visual Studioでこれらのファイルをビルドする際には、Custom Buildを使う必要がある。引数指定のなかで、インターフェイスファイルを先に、ソースファイルを後に書く。-a
-g obj.fsi obj.fsという具合である。
続いてサーバを。
module ServerTest
open System
open System.Threading
open System.Runtime.Remoting
open System.Runtime.Remoting.Channels
open System.Runtime.Remoting.Channels.Tcp
open Microsoft.FSharp.Idioms
#r @"obj.dll";;
open RemoteTest
let remoteObjectType = (typeof() : typ<MyRemoteObject>).result
let channel = new TcpChannel(16383)
do ChannelServices.RegisterChannel(channel, true)
do RemotingConfiguration.RegisterWellKnownServiceType(
remoteObjectType,
"MyRemoteObject",
WellKnownObjectMode.SingleCall)
let sync = new Object()
let _ = lock(sync) (
fun () -> Monitor.Wait(sync))
remoteObjectTypeがわかりにくい。F#には組み込みのtypeofがないので、こういう妙なことになる。lockはbooleanを返すので_にletしている。
そしてクライアント。
module ClientTest
open System
open System.Threading
open System.Runtime.Remoting
open System.Runtime.Remoting.Channels
open System.Runtime.Remoting.Channels.Tcp
open Microsoft.FSharp.Idioms
#r @"obj.dll";;
open RemoteTest
let remoteObjectType = (typeof() : typ<MyRemoteObject>).result
let channel = new TcpChannel()
do ChannelServices.RegisterChannel(channel, true)
let remote = Activator.GetObject(
remoteObjectType,
"tcp://localhost:16383/MyRemoteObject")
let msg = match remote with
| null -> "Remote object not found."
| _ ->
let remoteAsSimpleType = remote :?> MyRemoteObject
in remoteAsSimpleType.sayHello "World"
do Console.WriteLine(msg)
パターンマッチングで変数をletする。これがF#の醍醐味だ。
Posted by hajime at 2006年02月11日 04:18