13

実行時に以下と同等のことができるようにしたい:

var action = new Action<ANYTHING AT RUNTIME>(obj => Console.WriteLine("Called = " + obj));

アクションの正しいタイプを取得する必要があることはわかっていますが、Delegate.Create を使用して最終的なビットを取得する方法がわかりません。Typeアクション定義で T を表します。

var actionType = typeof(Action<>).MakeGenericType(Type);
var constructor = actionType.GetConstructors()[0];
var @delegate = Delegate.CreateDelegate(actionType, <WHAT GOES HERE>);

人々が欠けているように見える点は、Attribute から派生したクラスから使用されているため、T を静的に指定できない Action のインスタンスを作成しようとしているということです。つまり、T は何でもかまいません。一般的な定義

乾杯

4

6 に答える 6

5

実行する必要がある操作と、タイプに関係なく実行する方法がわかっている場合 (例のように)、操作を実行するジェネリック メソッドを作成し、その方法でデリゲートを作成してみませんか?

class Program
{
    public static void Perform<T>(T value)
    {
        Console.WriteLine("Called = " + value);
    }

    public static Delegate CreateAction(Type type)
    {
        var methodInfo = typeof (Program).GetMethod("Perform").MakeGenericMethod(type);
        var actionT = typeof (Action<>).MakeGenericType(type);
        return Delegate.CreateDelegate(actionT, methodInfo);
    }

    static void Main(string[] args)
    {
        CreateAction(typeof (int)).DynamicInvoke(5);
        Console.ReadLine();
    }
}
于 2012-09-22T06:29:45.907 に答える
0

次のコードを使用できます。型をオブジェクトにキャストできる場合に機能します。

Action<object> func = o => Console.WriteLine("Called = " + o.GetType().Name);
var actionType = typeof(Action<>).MakeGenericType(type);
var constructor = actionType.GetConstructors()[0];
var @delegate = Delegate.CreateDelegate(actionType, func.Method);

ただし、型が列挙型またはその他の値型の場合は機能しません。

于 2012-09-19T23:05:17.153 に答える
0

ジェネリック メソッドを作成して、目的のジェネリック パラメータを持つアクションを生成します。

private Action<T> CreateAction<T>() => 
             new Action<T>(obj => Console.WriteLine("Called = " + (object)obj)); 

次のように呼び出します。

var action = GetType()
            .GetMethod(nameof(CreateAction), BindingFlags.NonPublic | BindingFlags.Instance)
            ?.MakeGenericMethod(type)
            ?.Invoke(this, new object[]{});
于 2021-06-09T09:18:03.523 に答える
-1

次のコードを使用してデリゲートを作成します。これは型パラメーターでレイト バインドされます。「方法: リフレクションを使用してジェネリック型を調べてインスタンス化する」も参照してください。

abstract class ActionHelper {

    protected abstract Delegate CreateActionImpl();

    // A subclass with a static type parameter
    private class ActionHelper<T> : ActionHelper {
        protected override Delegate CreateActionImpl() {
            // create an Action<T> and downcast
            return new Action<T>(obj => Console.WriteLine("Called = " + (object)obj));
        }
    }

    public static Delegate CreateAction(Type type) {
        // create the type-specific type of the helper
        var helperType = typeof(ActionHelper<>).MakeGenericType(type);
        // create an instance of the helper
        // and upcast to base class
        var helper = (ActionHelper)Activator.CreateInstance(helperType);
        // call base method
        return helper.CreateActionImpl();
    }
}

// Usage
// Note: The "var" is always "Delegate"
var @delegate = ActionHelper.CreateAction(anyTypeAtRuntime);

つまり、この方法を使用することはお勧めしません。代わりに、

Action<object> action = obj => Console.WriteLine("Called = " + obj);

それは提供します

  • 同じ機能です。

    元のコードはパラメーターを"Called = " + obj"呼び出し.ToString()ます。上記も同様です。

  • 性能差なし。

    パラメータが値型の場合obj、両方のバリアントがボックス化操作を実行します。最初のボックス化は明らかではありませんが、"Called = " + obj"値の型をボックス化しています。

  • 短く、エラーが発生しにくい。

于 2012-09-09T12:34:35.540 に答える
-2

簡単な答えは、デリゲートを作成してからMyActionDelegate使用することです。

delegate void MyActionDelegate(T arg);
Delegate @delegate = new MyActionDelegate((a) => Console.WriteLine(a));

ジェネリック クラスを使用した実際の例を次に示します。

public class MyClass<T>
{
    public delegate void ActionDelegate(T arg);

    public void RunGenericAction(T arg)
    {
        var actionType = typeof(Action<>).MakeGenericType(typeof(T));
        var constructor = actionType.GetConstructors()[0];
        Delegate @delegate = new ActionDelegate((a) => { Console.WriteLine(arg); });
        var inst = (Action<T>)constructor.Invoke(new object[] { 
            @delegate.Target,  
            @delegate.Method.MethodHandle.GetFunctionPointer() 
        });
        inst(arg);
    }
}

123次のように使用すると、コンソールに出力されます。

var c = new MyClass<int>();
c.RunGenericAction(123);

に 2 つのパラメーターを渡していることに気付くでしょうConstructor.Invoke。これは、デリゲート引数が実際には 2 つの引数 (関数のターゲット オブジェクトと関数へのポインター) としてコンパイルされることがわかっているためです。私はそこでの華麗なフットワークの功績を認めることはできません。リフレクションを使用してデリゲート引数を渡す方法に関するこの優れた回答から「借りた」情報。

于 2012-08-26T16:37:17.347 に答える