C#中的函数指针

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

 FunctionPointer foo = // whatever, create the function pointer using mechanisms foo(); 

我不能使用一个可靠的委托(即使用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 functions = new Dictionary(); public A() { List ml = new List(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."); } } 

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

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

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

 class Program { static void Main(string[] args) { DynamicFunc f = par => { foreach (var p in par) Console.WriteLine(p); return null; }; f(1, 4, "Hi"); } } 

您可以将实例方法委托视为与Function类非常相似:对象和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); } 

然后:

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

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

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

这是您可以使用的另一部分代码; reflection速度相当慢,因此如果您希望频繁调用Dynamic函数调用,则不希望在委托中使用method.Invoke:

 public delegate void DynamicAction(params object[] parameters); static class DynamicActionBuilder { public static void PerformAction0(Action a, object[] pars) { a(); } public static void PerformAction1(Action a, object[] p) { a((T1)p[0]); } public static void PerformAction2(Action 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. } } 

这会快得多; 由于params样式的传递,每个动态调用将涉及每个param 1个typecheck,2个委托调用和一个数组构造。