C#中的函数指针

Mat*_*ley 12 c# reflection delegates

我想在某些方面(或两者)DelegateMethodInfo有资格获得这个头衔.但是,它们都没有提供我正在寻找的语法上的好处.所以,简而言之,有什么方法可以写下面的内容:

FunctionPointer foo = // whatever, create the function pointer using mechanisms
foo();
Run Code Online (Sandbox Code Playgroud)

我不能使用可靠的委托(即,使用delegate关键字来声明委托类型),因为直到运行时才能知道确切的参数列表.作为参考,这里是我目前在LINQPad中使用的内容,B用户生成的代码将在哪里(因此)Main,因此对我的用户来说非常好,我试图删除.Call:

void Main()
{
    A foo = new B();
    foo["SomeFuntion"].Call();
}

// Define other methods and classes here
interface IFunction {
    void Call();
    void Call(params object[] parameters);
}

class A {
    private class Function : IFunction {
        private MethodInfo _mi;
        private A _this;
        public Function(A @this, MethodInfo mi) {
            _mi = mi;
            _this = @this;
        }

        public void Call() { Call(null); }
        public void Call(params object[] parameters) {
            _mi.Invoke(_this, parameters);
        }
    }

    Dictionary<string, MethodInfo> functions = new Dictionary<string, MethodInfo>();

    public A() {
        List<MethodInfo> ml = new List<MethodInfo>(this.GetType().GetMethods());
        foreach (MethodInfo mi in typeof(Object).GetMethods())
        {
            for (int i = 0; i < ml.Count; i++)
            {
                if (ml[i].Name == mi.Name)
                    ml.RemoveAt(i);
            }
        }

        foreach (MethodInfo mi in ml)
        {
            functions[mi.Name] = mi;
        }
    }

    public IFunction this[string function] {
        get { 
            if (!functions.ContainsKey(function))
                throw new ArgumentException();

            return new Function(this, functions[function]);
        }
    }
}

sealed class B : A {
    public void SomeFuntion() {
        Console.WriteLine("SomeFunction called.");
    }
}
Run Code Online (Sandbox Code Playgroud)

Dan*_*ker 29

你说你想保持参数的数量和类型是开放的,但你可以用delgate做到这一点:

public delegate object DynamicFunc(params object[] parameters);
Run Code Online (Sandbox Code Playgroud)

这与您目前拥有的完全相同.试试这个:

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

                            return null;
                        };

        f(1, 4, "Hi");
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以将实例方法委托视为与您的Function类非常相似:对象和a MethodInfo.所以没有必要重写它.

C和C++中的函数指针也没有更接近你需要的东西:它们不能绑定到对象实例函数,它们也是静态类型的,不是动态类型的.

如果要在DynamicFunc委托中"包装"任何其他方法,请尝试以下操作:

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);
}
Run Code Online (Sandbox Code Playgroud)

然后:

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

f2("test", 100);
Run Code Online (Sandbox Code Playgroud)

请注意,我正在使用静态方法,Foo所以我传递null给实例,但如果它是一个实例方法,我将传递对象绑定到.Program碰巧是我的静态方法定义的类.

当然,如果传递错误的参数类型,那么在运行时会出现错误.我可能会寻找一种设计程序的方法,以便尽可能在编译时捕获尽可能多的类型信息.

  • 虽然我认为你是思考这个的天才,但是当我尝试使用以下命令创建委托时,我遇到了绑定错误:return(DynamicFunction)Delegate.CreateDelegate(typeof(DynamicFunction),this,functions [function]); (4认同)
  • 好吧,也许不那么复杂......请参阅更新. (2认同)
  • 足够公平 - 用爱因斯坦的话来说,一个程序应尽可能是静态类型的,但不是静态类型的. (2认同)