4

我正在 c# 和 asp.net 中迈出第一步,我非常享受它。现在,我有一个问题...... C# 中是否有一个函数可以像在 php 中一样调用类/方法?
例如:

$class = array(
    "foo", // class name
    "bar" // method name
);
$params = array(
    "one",
    "two"
);
call_user_func_array($class, $params); //execute Foo->bar("one","two");
4

3 回答 3

3

不,没有任何内置功能可以做到这一点。您可以构建一个使用反射执行类似操作的方法,但这似乎是寻找问题的解决方案。

void Main()
{
    CallUserFuncArray("UserQuery+Foo", "Bar", "One", "Two");
}

// Define other methods and classes here
public class Foo
{
    public static void Bar(string a, string b){}
}

public void CallUserFuncArray(string className, string methodName, params object[] args)
{
    Type.GetType(className).GetMethod(methodName).Invoke(null, args);
}
于 2012-10-22T03:07:17.243 回答
2

正如其他人所指出的,有多种方法可以模拟这一点,但 C# 中没有“烘焙”功能。最灵活的方法是使用反射,但如果您事先知道将要调用的方法列表,则可以采用更简单(也更容易处理)的方式。

class Foo
{
    public static string FooA(int p1, int p2) 
    { 
        return "FooA:" + p1 + p2; 
    }
    public static string FooB(int p1, int p2) { return "FooB:" + p1 + p2; }
    public static string FooC(int p1, int p2) { return "FooC:" + p1 + p2; }
}    
class Bar
{
    //You can use Func<int, int, object> instead of a delegate type,
    //but this way is a little easier to read.
    public delegate string Del(int p1, int p2);

    public static string DoStuff()
    {        
        var classes = new Dictionary<string, Dictionary<string, Del>>();
        classes.Add("Foo", new Dictionary<string, Del>());
        classes["Foo"].Add("FooA", Foo.FooA);
        classes["Foo"].Add("FooB", Foo.FooB);
        classes["Foo"].Add("FooC", Foo.FooC);

        //...snip...

        return classes["Foo"]["FooA"](5, 7);
    }
}

顺便说一句,这确实有效。

如果您知道要以这种方式提供哪些方法,我建议您重新考虑您尝试执行的操作。我能想到的使用字符串来选择执行路径的唯一原因是,如果您打算从用户那里获取这些字符串。像这样暴露应用程序的内部细节不仅是一个巨大的禁忌,而且它非常接近eval-type 功能。C# 没有eval方法是有原因的,并不是因为设计者忘记把它放进去。

于 2012-10-22T05:10:33.863 回答
1

正如@StriplingWarrior 所说,没有内置的等价物call_user_func_array,但您可以使用反射做类似的事情。

问题是反射代码很快就会变得非常复杂,如果你不是很小心,它会变得脆弱和容易出错。

例如,以下功能可以满足您的要求:

public static void CallUserFuncArray(string[] func, params string[] args)
{
    var type = Type.GetType(func[0]);
    if (type == null)
    {
        throw new ArgumentException("The specified Class could not be found");
    }

    var method = type.GetMethod(func[1], BindingFlags.Static | BindingFlags.Public);
    if (method== null)
    {
        throw new ArgumentException("The specified Method could not be found");
    }

    method.Invoke(null, args);
}

你这样称呼它:

var func = new [] { "Foo", "Bar" };
var args = new [] { "one", "two" };

CallUserFuncArray(func, args);

问题虽然很多。

  • 该代码仅在Bar是公共静态方法时才有效。
  • 如果您需要在对象上调用实例方法,则会出现全新的复杂层。
  • args如果数组中的参数不适合目标方法,代码将会爆炸。
  • 这里不支持调用除了字符串参数之外的任何方法。可以在调用“Invoke”之前查询该方法预期的参数类型并转换类型,但您会变得更加混乱。
  • 如果您需要满足这些情况,还有更多的边缘情况会进一步破坏此代码的复杂性。

套用卡尔富兰克林(dotNetRocks 成名):

我有一个需要解决的问题,所以我使用了反射。现在我有两个问题。

如果您发现自己需要做这种事情,那么您可能需要重新考虑您的整体设计。

于 2012-10-22T04:03:34.953 回答