问题描述
我想在某些方面,Delegate
或 MethodInfo
中的一个(或两者)都符合这个标题.但是,两者都没有提供我正在寻找的语法上的好处.所以,简而言之,有什么方法可以写出以下内容:
I suppose in some ways either (or both) Delegate
or MethodInfo
qualify for this title. However, neither provide the syntactic niceness that I'm looking for. So, in short, Is there some way that I can write the following:
FunctionPointer foo = // whatever, create the function pointer using mechanisms
foo();
我不能使用实体委托(即,使用 delegate
关键字来声明委托类型),因为直到运行时才能知道确切的参数列表.作为参考,这是我目前在 LINQPad 中一直在玩的东西,其中 B
将(大部分)是用户生成的代码,Main
也是如此,因此为了美观我的用户,我正在尝试删除 .Call
:
I can't use a solid delegate (ie, using the delegate
keyword to declare a delegate type) because there is no way of knowing till runtime the exact parameter list. For reference, here's what I've been toying with in LINQPad currently, where B
will be (mostly) user generated code, and so will Main
, and hence for nicety to my users, I'm trying to remove the .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.");
}
}
推荐答案
你说你想保持参数的数量和类型是开放的,但是你可以用一个 delgate 来做到这一点:
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");
}
}
您可以将实例方法委托与您的 Function
类非常相似:一个对象和一个 MethodInfo
.所以没必要重写.
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.
此外,C 和 C++ 中的函数指针并不符合您的需要:它们不能绑定到对象实例和函数,而且它们是静态类型的,而不是动态类型的.
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.
如果您想在 DynamicFunc 委托中包装"任何其他方法,请尝试以下操作:
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);
}
然后:
DynamicFunc f2 = MakeDynamicFunc(null, typeof(Program).GetMethod("Foo"));
f2("test", 100);
请注意,我使用的是静态方法 Foo
,因此我为实例传递 null
,但如果它是实例方法,我将传递对象绑定到.Program
恰好是我定义静态方法的类.
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.
这篇关于C#中的函数指针的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!