DotNet オブジェクトおよびクラスの寿命制御

3ds Max 2010 より前のバージョンでは、MAXScript のガベージ コレクションを実行すると DotNet イベント ハンドラが削除されるタイミングが早すぎるという問題が発生します。

3ds Max 2010 以降 のメソッドでは、MAXScript の代わりに DotNet で処理される、対応するオブジェクトの寿命制御を設定することでこの問題を回避することができます。

dotNet.setLifetimeControl {<dotNetObject> | <dotNetClass>} {#mxs | #dotnet}

DotNet オブジェクトまたは DotNet クラスをラップする MAXScript 値を、その値への MAXScript 参照がない場合にガベージ コレクションの対象にするかどうか(#mxs)、または MAXScript 値にガベージ コレクションを実行する前に、DotNet オブジェクトを破棄するかどうか(#dotnet)をコントロールします。

既定では、dotNetObject 値は DotNet オブジェクトに対して強参照を保持し、DotNet オブジェクトは dotNetObject 値が削除された場合にのみ削除されます。これは、上記のメソッドで #mxs を 2 番目の引数として指定した場合と同等です。

#dotnet を 2 番目の引数として指定すると、DotNet オブジェクトが削除されるまで dotNetObject のコレクションは実行できません。dotNetObject 値は DotNet オブジェクトに対して弱参照を保持しており、DotNet オブジェクトは、他の DotNet オブジェクトがそのオブジェクトに対する参照を保持していない場合に DotNet ガベージ コレクションが実行されると削除されます。

例 1 - ハンドラが削除される

    (
    function whenButtonIsPressed =
    (
    print "Pressed from a .NET button"
    )
    function formIsClosed =
    (
    print "form closed"
    )
    local mButton = dotNetObject "System.windows.forms.button"
    mButton.text = ".NET Button"
    mButton.size = dotNetObject "System.Drawing.Size" 100 100
    mButton.location = dotNetObject "System.Drawing.Point" 50 50
    local hForm = dotNetObject "System.Windows.Forms.Form"
    hForm.controls.add mButton
    dotNet.addEventHandler mButton "click" whenButtonIsPressed
    dotNet.addEventHandler hForm "Closed" formIsClosed
    hForm.show()
    ok
    )
    gc()

上のコードを評価すると、DotNet ボタンと 2 つのイベント ハンドラを持った DotNet フォームが作成されます。イベント ハンドラの 1 つはボタンが押されたときにリスナーにメッセージを出力するもので、もう 1 つはフォームが閉じられたときにメッセージを出力するものです。

ただし、フォームの作成後に MAXScript ガベージ コレクションが実行されるため、どちらのハンドラもすぐに削除され、ボタンを押してもフォームを閉じても何も出力されません。

例 2 - ハンドラを保持

ボタンとフォームの寿命制御を DotNet に引き渡すことにより、MAXScript ガベージ コレクション後も両方のボタンのイベント ハンドラを保持することができます。

    (
    function whenButtonIsPressed =
    (
    print "Pressed from a .NET button"
    )
    function formIsClosed =
    (
    print "form closed"
    )
    local mButton = dotNetObject "System.windows.forms.button"
    mButton.text = ".NET Button"
    mButton.size = dotNetObject "System.Drawing.Size" 100 100
    mButton.location = dotNetObject "System.Drawing.Point"50 50
    local hForm = dotNetObject "System.Windows.Forms.Form"
    hForm.controls.add mButton
    dotNet.addEventHandler mButton "click" whenButtonIsPressed
    dotNet.addEventHandler hForm "Closed" formIsClosed
    dotNet.setLifetimeControl mButton #dotnet
    dotNet.setLifetimeControl hForm #dotnet
    hForm.show()
    ok
    )
    gc()