Pertanyaan Membangun Delegasi dari MethodInfo?


Setelah googling dan mendarat di SO dan setelah membaca pertanyaan lain ini

Apakah mungkin untuk membangun Delegasi yang benar dari MethodInfo jika Anda tidak tahu jumlah atau jenis parameter pada waktu kompilasi?

Lebih lanjut tentang ini: bisakah ini dilakukan secara elegan tanpa menggunakan Refleksi. Kirim atau ketik pembangun?

Ini agak menyebalkan bagi saya karena Delegate.CreateDelegate mengharuskan saya untuk menentukan tipe Delegasi yang benar sebagai parameter pertama atau yang lain itu akan melemparkan pengecualian atau memanggil metode yang salah.

Saya sedang membangun beberapa roda ninja dan ini akan sangat membantu ... Terima kasih!


Berikut ini solusi umum:

/// <summary>
/// Builds a Delegate instance from the supplied MethodInfo object and a target to invoke against.
/// </summary>
public static Delegate ToDelegate(MethodInfo mi, object target)
{
    if (mi == null) throw new ArgumentNullException("mi");

    Type delegateType;

    var typeArgs = mi.GetParameters()
        .Select(p => p.ParameterType)
        .ToList();

    // builds a delegate type
    if (mi.ReturnType == typeof(void)) {
        delegateType = Expression.GetActionType(typeArgs.ToArray());

    } else {
        typeArgs.Add(mi.ReturnType);
        delegateType = Expression.GetFuncType(typeArgs.ToArray());
    }

    // creates a binded delegate if target is supplied
    var result = (target == null)
        ? Delegate.CreateDelegate(delegateType, mi)
        : Delegate.CreateDelegate(delegateType, target, mi);

    return result;
}

Catatan: Saya sedang membangun aplikasi Silverlight yang akan menggantikan aplikasi javascript yang dibangun tahun lalu di mana saya memiliki beberapa antarmuka Javascript yang memanggil metode Silverlight [ScriptableMember] yang sama.

Semua antarmuka JS lama perlu didukung serta antarmuka baru untuk mengakses fitur baru, sehingga sesuatu yang secara otomatis mengatur antarmuka JS dan "mendelegasikan" panggilan ke metode Silverlight yang tepat akan membantu mempercepat pekerjaan.

Saya tidak bisa memposting kode di sini, jadi itulah ringkasannya.


32
2017-07-14 10:28


asal


Jawaban:


Sejujurnya, jika Anda tidak tahu jenis pada waktu kompilasi, tidak ada banyak manfaat dalam membuat Delegate. Anda tidak ingin menggunakannya DynamicInvoke; itu akan menjadi lambat sebagai refleksi. Pengecualian utama untuk ini adalah ketika ada tipe delegasi yang bersembunyi di bayang-bayang, misalnya ketika berlangganan suatu acara - dalam hal ini EventInfo membuat ini tersedia.

Untuk info, dalam .NET 3.5 pada Expression, ada:

Expression.GetActionType(params Type[] typeArgs);
Expression.GetFuncType(params Type[] typeArgs)

Itu mungkin membantu sejauh ini:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
static class Program {
    static void Main() {
        DoStuff("Test1");
        DoStuff("Test2");
    }
    static void DoStuff(string methodName) {
        MethodInfo method = typeof(Program).GetMethod(methodName);
        List<Type> args = new List<Type>(
            method.GetParameters().Select(p => p.ParameterType));
        Type delegateType;
        if (method.ReturnType == typeof(void)) {
            delegateType = Expression.GetActionType(args.ToArray());
        } else {
            args.Add(method.ReturnType);
            delegateType = Expression.GetFuncType(args.ToArray());
        }
        Delegate d = Delegate.CreateDelegate(delegateType, null, method);
        Console.WriteLine(d);
    }
    public static void Test1(int i, DateTime when) { }
    public static float Test2(string x) { return 0; }
}

22
2017-07-14 10:36



Jika Anda tidak tahu nomor atau jenis parameter di muka, mungkin itu berarti Anda tidak tahu tipe delegasi yang ingin Anda buat juga?

Jika itu masalahnya, Anda terjebak dalam kasus yang benar-benar umum.

Namun, untuk sebagian besar umum kasus (tidak ada parameter ref / out, beberapa parameter yang cukup untuk menggunakan salah satu dari jenis yang ada), Anda bisa lolos dengan salah satu dari Func atau Action delegasi. (.NET 4.0 memiliki Func/Action jenis untuk sejumlah besar parameter, sehingga benar-benar Anda hanya perlu khawatir tentang parameter keluar / ref.) Jika metode memiliki jenis kembali tipe non-kekosongan Func, jika tidak, gunakan Action. Cari tahu jenis apa yang akan digunakan berdasarkan jumlah parameter, mis.

static readonly Type[] FuncTypes = { typeof(Func), 
    typeof(Func<>), typeof(Func<,>), typeof(Func<,,>), /* etc */ };

Menggunakan Type.MakeGenericType menggunakan tipe parameter dan jenis kembalian untuk mendapatkan tipe delegasi yang tepat, lalu Delegate.CreateDelegate harus bekerja.

Saya tidak punya waktu untuk membuat sampel sekarang, tetapi beri tahu saya jika Anda menginginkan saya nantinya.

Satu pertanyaan: bagaimana Anda akan menggunakan delegasi ini? Sesuatu yang lain harus tahu cara mengeksekusinya, pasti ...


7
2017-07-14 10:34



Kenapa itu rumit?

public static Delegate CreateDelegate(this MethodInfo method)
{
    return Delegate.CreateDelegate
    (
        Expression.GetDelegateType
        (
            method.GetParameters()
                .Select(p => p.ParameterType)
                .Concat(new Type[] { method.ReturnType })
                .ToArray()
        ),
        null,
        method
    );   
}

[Catatan sampingan: Saya awali metode ini "Buat ...". "Untuk ..." membingungkan karena menyesatkanmu untuk berpikir itu adalah konversi.]


6
2017-12-28 08:43