1

Silverlight 5 で動作する次のコードがあります。

public void Send(Notification notification)
{
    // Because the variable is passed as Notification, we have to trick the
    // type-inference feature of the runtime so the message will be sent using
    // the actual type of the object.
    // Using the dynamic keyword, we can convert the type of the object passed
    // to the Send method.
    // This allows subscribers to register for messages using the generic interface.
    dynamic stronglyTypedNotification = Convert.ChangeType(notification,
                                                           notification.GetType(),
                                                           CultureInfo.InvariantCulture);

    SendCore(stronglyTypedNotification);
}

private void SendCore<T>(T notification)
    where T : Notification
{
    foreach (var handlerFactory in Handlers)
    {
        var handler = handlerFactory.Value as INotificationHandler<T>;

        if (handler != null)
        {
            handler.Handle(notification);
        }
    }
}

WPF アプリケーションで実行するには、このコードを移植する必要があります。

WPF アプリケーションで実行し、SendCore メソッド内にブレークポイントを設定すると、T は正しい型ではありません。これは、ジェネリックが静的に定義されているため、コンパイラが実行時に必要と思われるバージョンの SendCore を作成したためだと推測できます。このコードは SL で完全に機能するため、Silverlight ではこれを別の方法で処理していると思います。

このコードの目的は、INotificationHandler を実装する Handlers コレクションに含まれる任意のオブジェクトを見つけることです。ここで、T は Send メソッド (基本 Notification クラスをサブクラス化する) に渡されるオブジェクトの型であり、次に Handle(T n) メソッドを呼び出します。それらのオブジェクト。

私のWPFアプリでこれを行うにはどうすればよいですか?

アップデート

いくつかの追加テストの後、私はより独特な結果を見つけています。SendCore メソッドの最初の行にブレークポイントを設定し、T と通知を調べると、次のことがわかります。

  • Intellisense は、T がアセンブリ内の正当なクラスである "GenericNotification" であることを示します。
  • Intellisense は、「通知」が厳密に型指定された正しいクラス (DataChangedNotification) であることを示します。
  • DataChangedNotification は、いかなる方法でも GenericNotification をサブクラス化しません。どちらも Notification のサブクラスです。
  • T は GenericNotification に解決されるため、各ハンドラーを INotificationHandler<T> にキャストしようとしても、INotificationHandler<GenericNotification> を実装していないため失敗します。

この正確なコードが Silverlight、コンソール アプリケーション、および別の WPF アプリケーション (および LINQpad での David のテスト) で機能することを考えると、いったい何が起こっているのでしょうか?

私が言及できる唯一のことは、WPF アプリケーションによって参照されるクラス ライブラリにコードが実際に存在するということです。別の(新しい)WPFアプリケーションでそのシナリオをテストし、正しい結果が得られたため、それが問題かどうかはわかりません。

4

2 に答える 2

1

それは私にとってはうまくいき、それは期待されています。違っていたらビックリしました。

void Main()
{
    Send(new NA());
    Send(new NB());
}

public class Notification {}
public class NA : Notification {}
public class NB : Notification {}

public void Send(Notification notification)
{
    dynamic stronglyTypedNotification
        = Convert.ChangeType(notification,
                             notification.GetType(),
                             CultureInfo.InvariantCulture);

    SendCore(stronglyTypedNotification);
}

public void SendCore<T>(T notification) where T : Notification
{
    Console.WriteLine(typeof(T));
}

これは出力します

typeof (NA) 
typeof (NB)
于 2012-09-20T07:20:06.877 に答える
1

明らかな性格の衝突にもかかわらず、私はダニエルが問題をより深く掘り下げ続けるように促してくれたことに感謝します. 同時に、それが他の誰にも価値を提供していないと思うので、それを削除することを要求しています.

結局のところ、問題は別の場所で発生しており、単純な ToString() オーバーロードによってマスクされていました。

最初の問題: 私が見た動作 (およびレポート) は、別の開発者が、データ型ではなくオブジェクトの名前をデバッガーに表示する基本通知クラスに ToString オーバーライドを追加した結果です。これが、VS で「通知」パラメーターを確認すると、予想される型名が表示された理由です。実際には、渡されるオブジェクトのタイプは GenericNotification でした。

これが起こっていることに気づいたら、フレームワーク コード (独立して構築された別のソリューション) を開いて、オブジェクトがインスタンス化された場所を確認することができました。そこで私は、ファイルの .NET バージョンが Silverlight バージョンとは異なる方法で実装されていることを発見しました。依存関係の挿入には MEF を使用し、Silverlight バージョンのコードは、サポートされている型のインポートされたリストに対してデータ型を解決していました。.NET バージョンでは、switch ステートメントが使用されていました (うわっ!)。

そこで、.NET のバージョンを変更して、MEF を使用してオブジェクトを動的に作成し、型とビオラを解決できるようにしました。現在、すべてが期待どおりに機能しており、プレッシャーが軽減されています (これはソフトウェアの重要な機能であるため、機能していません...)。

于 2012-09-26T19:14:45.410 に答える