0

Silverlight - JavaScript の相互運用性を多用する既存のコードに適切な例外処理を追加するのに問題があります。この場合、私の JavaScript は、Silverlight で有意義に処理したい例外をスローできます。

Silverlight から JavaScript オブジェクトのインスタンスを作成し、後でそのオブジェクトのメソッドを呼び出しています。

public class MyWrapper
{
    dynamic _myJSObject;

    public MyWrapper()
    {
        _myJSObject = HtmlPage.Window.CreateInstance("MyJSObject");
    }

    public int MyMethod()
    {
        try
        {
            int result = (int)_myJSObject.MyMethod();
        }
        catch (Exception ex)
        {
            // I want to add meaningful exception handling here
        }      
    }
}

MyJSObject.MyMethod例外がスローされるたびに、次の 2 つの問題があります。

  • ブラウザーに、例外が発生したというメッセージが表示されます。
  • 例外に関する情報がマネージ コードに渡されません。代わりに、RuntimeBinderException「非デリゲート型を呼び出すことはできません」というだけで、他の情報はまったく含まれていません。これは、ここで説明されている内容と一致しないようです。私は期待していInvalidOperationExceptionます。

メソッドの戻り値をキャストすることを避けようとしました:

object tmp= _myJSObject.MyMethod();

これは違いはありません。JavaScript 側でスローされる例外のタイプを変更しても効果はありません。

MyJSObject.prototype.MyMethod = function ()
                                {
                                    throw "Hello Silverlight!";
                                }

私が今考えることができる唯一の解決策は、関数の戻り値を悪用して例外に関する情報を渡すことですが、それは私のコードをずっと醜くします...そう:

表示されている動作がドキュメントに記載されている動作と異なるのはなぜですか? それはどういうわけか私の使用と関係がありdynamicますか? マネージ コード内の JavaScript で発生する例外を適切に処理するにはどうすればよいですか?

4

1 に答える 1

0

かなりの実験を重ねた結果、Silverlight から JavaScript 例外を直接処理する方法はないと結論付けました。例外を処理できるようにするには、JavaScript コードを少し変更する必要があります。

エラーをスローする代わりに、次のように返します。

function MyMethod()
{
    try
    {
        // Possible exception here
    }
    catch (ex)
    {
        return new Error(ex);
    }
}

次に、Silverlight 側で、ラッパーを使用しScriptObjectて戻り値を再び例外に変換します。ここで重要なのはTryInvokeMemberメソッドです。

public class ScriptObjectWrapper : DynamicObject
{
    private ScriptObject _scriptObject;

    public ScriptObjectWrapper(ScriptObject scriptObject)
    {
        _scriptObject = scriptObject;
    }

    public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
    {
        result = _scriptObject.Invoke(binder.Name, args);

        ScriptObject s = result as ScriptObject;
        if (s != null)
        {
            // The JavaScript Error object defines name and message properties.
            string name = s.GetProperty("name") as string;
            string message = s.GetProperty("message") as string;
            if (name != null && message != null && name.EndsWith("Error"))
            {
                // Customize this to throw a more specific exception type
                // that also exposed the name property.
                throw new Exception(message);
            }
        }

        return true;
    }

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        try
        {
            _scriptObject.SetProperty(binder.Name, value);
            return true;
        }
        catch
        {
            return false;
        }
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        try
        {
            result = _scriptObject.GetProperty(binder.Name);
            return true;
        }
        catch
        {
            result = null;
            return false;
        }
    }

}

このラッパーを改善して、実際に JavaScript の try-catch メカニズムを透過的に挿入できるようにすることもできますが、私の場合は JavaScript ソース コードを直接制御していたので、これを行う必要はありませんでした。

Error組み込みの JavaScriptオブジェクトを使用する代わりに、nameプロパティがError.

ラッパーを使用するには、元のコードを次のように変更します。

public MyWrapper()
{
    _myJSObject = new ScriptObjectWrapper(
                  HtmlPage.Window.CreateInstance("MyJSObject"));
}
于 2012-08-27T14:28:22.520 に答える