Указатели функции в C#

перечисляют

Обертка, которую перечисляет повторяемое с, и она приведет к объекту наряду со своим индексом.

, Например:


>>> a = ['a', 'b', 'c', 'd', 'e']
>>> for index, item in enumerate(a): print index, item
...
0 a
1 b
2 c
3 d
4 e
>>>

Ссылки:

12
задан Matthew Scharley 26 July 2009 в 11:52
поделиться

2 ответа

You say you want to keep the number and type of parameters open, but you can do that with a delgate:

public delegate object DynamicFunc(params object[] parameters);

This is exactly the same thing you currently have. Try this:

class Program
{
    static void Main(string[] args)
    {
        DynamicFunc f = par =>
                        {
                            foreach (var p in par)
                                Console.WriteLine(p);

                            return null;
                        };

        f(1, 4, "Hi");
    }
}

You can think of an instance-method delegate as very similar to your Function class: an object an a MethodInfo. So there's no need to rewrite it.

Also function pointers in C and C++ are not any closer to what you need: they cannot be bound to an object instance and function, and also they are statically typed, not dynamically typed.

If you want to "wrap" any other method in a DynamicFunc delegate, try this:

public static DynamicFunc MakeDynamicFunc(object target, MethodInfo method)
{
    return par => method.Invoke(target, par);
}

public static void Foo(string s, int n)    
{
    Console.WriteLine(s);
    Console.WriteLine(n);
}

and then:

DynamicFunc f2 = MakeDynamicFunc(null, typeof(Program).GetMethod("Foo"));

f2("test", 100);

Note that I'm using a static method Foo so I pass null for the instance, but if it was an instance method, I'd be passing the object to bind to. Program happens to be the class my static methods are defined in.

Of course, if you pass the wrong argument types then you get errors at runtime. I'd probably look for a way to design your program so that as much type information is captured at compile time as possible.

29
ответ дан 2 December 2019 в 04:43
поделиться

Вот еще один фрагмент кода, который вы можете использовать; Отражение происходит довольно медленно, поэтому, если вы ожидаете, что ваши вызовы динамических функций будут часто вызываться, вам не нужен метод. Invoke внутри делегата:

public delegate void DynamicAction(params object[] parameters);
static class DynamicActionBuilder
{
    public static void PerformAction0(Action a, object[] pars) { a(); }
    public static void PerformAction1<T1>(Action<T1> a, object[] p) {
        a((T1)p[0]);
    }
    public static void PerformAction2<T1, T2>(Action<T1, T2> a, object[] p) {
        a((T1)p[0], (T2)p[1]);
    }
    //etc...

    public static DynamicAction MakeAction(object target, MethodInfo mi) {
        Type[] typeArgs =
            mi.GetParameters().Select(pi => pi.ParameterType).ToArray();
        string perfActName = "PerformAction" + typeArgs.Length;
        MethodInfo performAction =
            typeof(DynamicActionBuilder).GetMethod(perfActName);
        if (typeArgs.Length != 0)
            performAction = performAction.MakeGenericMethod(typeArgs);
        Type actionType = performAction.GetParameters()[0].ParameterType;
        Delegate action = Delegate.CreateDelegate(actionType, target, mi);
        return (DynamicAction)Delegate.CreateDelegate(
            typeof(DynamicAction), action, performAction);
    }
}

И вы можете использовать его так:

static class TestDab
{
    public static void PrintTwo(int a, int b) {
        Console.WriteLine("{0} {1}", a, b);
        Trace.WriteLine(string.Format("{0} {1}", a, b));//for immediate window.
    }
    public static void PrintHelloWorld() {
        Console.WriteLine("Hello World!");
        Trace.WriteLine("Hello World!");//for immediate window.
    }

    public static void TestIt() {
        var dynFunc = DynamicActionBuilder.MakeAction(null,
            typeof(TestDab).GetMethod("PrintTwo"));
        dynFunc(3, 4);
        var dynFunc2 = DynamicActionBuilder.MakeAction(null,
            typeof(TestDab).GetMethod("PrintHelloWorld"));
        dynFunc2("extraneous","params","allowed"); //you may want to check this.
    }
}

Это будет довольно много Быстрее; каждый динамический вызов будет включать 1 проверку типа для каждого параметра, 2 вызова делегата и одну конструкцию массива из-за передачи в стиле параметров.

3
ответ дан 2 December 2019 в 04:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: