3

動的キャストを行うために他の回答のいくつかを読んだことがありますが、解決したい状況にそれらが対処しているかどうかわからないため、質問です。

私はインターフェースを持っています

public interface ICustomTransmitter<T> : IDataTransmitter where T : EventArgs
{
    event EventHandler<T> DataEvent;
}

実行時にジェネリック型引数を取得できる関数のセット。これは、そのタイプにキャストし、特定のイベントをフックするためです (これは考えられたコードなので、優しくしてください)。

public bool IsTypeOf(Type baseType, Type interfaceType,
    out Type argumenType)
{
    var interfaces = baseType.GetInterfaces();
    argumenType = null;

    foreach (Type @interface in interfaces)
    {
        if (@interface.Name != interfaceType.Name) continue;
        if (@interface.IsGenericType)
        {
            argumenType = @interface.GetGenericArguments()[0];
        }
        return true;
    }
    return false;
}

そして、上記の魔法を使う関数

Type argument;
var generic = typeof (ICustomTransmitter<>);
if (IsTypeOf(receiver.GetType(),generic ,out argument))
{
    var created = generic.MakeGenericType(new[] {argument});

    //the line of code missing is below
    receiver as created 
}

レシーバーをその作成されたタイプにキャストすることは可能ですか? また、ドット ネット 3.5 とドット ネット 4 の両方で機能するソリューションが必要です。

4

2 に答える 2

2

それを行うキャスティングの種類はありません。キャストとは、実行時の型が既知のコンパイル時の型であるかどうかを確認することです。コンパイル時の型さえありません。

必要なことは、リフレクションを使用してインターフェイスを探し、ジェネリック型引数を抽出し、互換性のあるデリゲートを作成し、デリゲートのハンドラーをフックすることです。の最初の数ステップを完了しましたIsOfType

イベント ハンドラーを接続すると、そのaddメソッドが呼び出されます。コンパイラは、このメソッドに「add_EventName」という形式の名前を生成します。これらすべてを実行するサンプル コードを次に示します。

using System;
using System.Reflection;

public class Program
{
    public static void Main(string[] args)
    {
        object o = new CustomArgsTransmitter();

        // make sure we've got the interface
        var interf = o.GetType().GetInterface("ICustomTransmitter`1");

        // get the arg type.
        var argType = interf.GetGenericArguments()[0];

        // create a delegate for the handler based on the arg type above
        var handlerMethodInfo = typeof(Program).GetMethod("Handler", BindingFlags.Static | BindingFlags.Public)
        var del = Delegate.CreateDelegate(typeof(EventHandler<>).MakeGenericType(argType), handlerMethodInfo);

        // Invoke the add method of the event.
        o.GetType().InvokeMember("add_DataEvent", BindingFlags.InvokeMethod, null, o, new object[] { del });

        //  just test code at this point.
        // fire event to make sure it is signed up.
        // It should print a message to the console.
        ((CustomArgsTransmitter)o).FireEvent();

    }

    public static void Handler(object sender, EventArgs e)
    {
        Console.WriteLine("Got event {0} from {1}", e, sender);
    }
}

public interface IDataTransmitter { }

public interface ICustomTransmitter<T> : IDataTransmitter where T : EventArgs
{
    event EventHandler<T> DataEvent;
}

public class MyArgs : EventArgs { }

public class CustomArgsTransmitter : ICustomTransmitter<MyArgs>
{
    public event EventHandler<MyArgs> DataEvent;

    public void FireEvent()
    {
        DataEvent(this, new MyArgs());
    }
}
于 2013-08-24T08:15:36.487 に答える
1

いいえ。コンパイル時に不明な型に式をキャストすることはできません。(「既知」とはType、ジェネリック型パラメーターが閉じている に解決可能であることを意味します。)

そうは言っても、式APIを使えば可能かもしれないと思います。決定した型 (厳密に型指定できる) のラムダ式を作成し、それをコンパイルしてから、オブジェクトで実行してキャストを実行するという考え方です。これを 100% 行う必要がある場合は、それが私が目指す方向です。

于 2013-08-24T07:22:08.443 に答える