c # выполнить строку как код - PullRequest
5 голосов
/ 02 октября 2009

Вот что я хочу сделать, и я знаю, что это возможно с Perl, PHP, Python и Java, но я работаю с C #

как мне сделать следующее:

public void amethod(string functionName)
{
    AVeryLargeWebServiceWithLotsOfMethodsToCall.getFunctionName();
}

Я хочу передать functionName в метод, и я хочу, чтобы он выполнялся, как указано выше.

Как это можно сделать?

Нужно ли мне ANTLR или любой другой инструмент для этого?

Спасибо.

Ответы [ 6 ]

7 голосов
/ 02 октября 2009

Вы можете выполнить метод по имени через Reflection. Вам необходимо знать тип, а также имя метода (это может быть тип текущего объекта, метод другого объекта или статический тип). Похоже, вы хотите что-то вроде:

public void amethod(string functionName) 
{
    Type type = typeof(AVeryLargeWebServiceWithLotsOfMethodsToCall);
    MethodInfo method = type.GetMethod(functionName, BindingFlags.Public | BindingFlags.Static);
    method.Invoke(null,null); // Static methods, with no parameters
}

Редактировать в ответ на комментарий:

Звучит так, будто вы действительно хотите получить результат от этого метода. Если это так, учитывая, что это все еще статический метод в службе (что я и думаю, учитывая то, что вы написали), вы можете сделать это. MethodInfo.Invoke будет возвращать возвращаемое значение метода как объект напрямую, поэтому, например, если вы возвращали строку, вы можете сделать:

public string amethod(string functionName) 
{
    Type type = typeof(AVeryLargeWebServiceWithLotsOfMethodsToCall);
    MethodInfo method = type.GetMethod(functionName, BindingFlags.Public | BindingFlags.Static);
    object result = method.Invoke(null,null); // Static methods, with no parameters
    if (result == null)
        return string.Empty;
    return result.ToString();
    // Could also be return (int)result;, if it was an integer (boxed to an object), etc.
}
5 голосов
/ 02 октября 2009

Выполнение строки, как если бы это было кодом, возможно в c #, но это не красиво и не просто. Это также считается плохой практикой и небезопасным (вы, вероятно, должны избегать этого и в динамических языках).

Вместо этого сделайте что-то вроде этого:

public void amethod(Action actionParam)
{
    actionParam();
}

Теперь в вашем случае вы хотите вызвать веб-сервис. Поскольку в конечном итоге это сводится к XML, у вас есть несколько вариантов:

  • Обходите встроенную систему для вызова веб-сервисов и создайте собственный веб-запрос с правильным именем в правильном месте в XML.
  • Создайте делегатов для каждого из методов в службе для передачи, возможно, с помощью отражения.
4 голосов
/ 02 октября 2009

Вы говорите, что AVeryLargeWebServiceWithLotsOfMethodsToCall - это экземпляр объекта, для которого вы хотите вызвать метод с именем functionName? Если так:

MethodInfo method = AVeryLargeWebServiceWithLotsOfMethodsToCall.GetType().GetMethod(functionName);
method.Invoke(AVeryLargerWebServiceWithLotsOfMethodsToCall, null);

Или AVeryLargeWebServiceWithLotsOfMethodsToCall тип, для которого вы хотите вызвать статический метод с именем functionName? Если так:

MethodInfo method = typeof(AVeryLargeWebServiceWithLotsOfMethodsToCall).GetMethod(functionName);
method.Invoke(null, null);
3 голосов
/ 02 октября 2009

Это можно сделать с помощью отражения. Тем не менее, я считаю, что вам нужна ссылка на объект, чтобы пойти с ним.

Пример из здесь

Type t = this.GetType();
MethodInfo method = t.GetMethod("showMessage");
method.Invoke(this, null);

В качестве альтернативы вы можете использовать Action или какой-либо другой делегат для передачи ссылки на функцию, которую вы хотите вызвать.

public void amethod(Action function)
{
    function();
}
1 голос
/ 03 октября 2009

Почему бы вам просто не использовать .NET Remoting? Это сделано именно для этого.

Совершенно другим решением было бы использование класса CSharpCodeCompiler.

0 голосов
/ 13 июня 2012

Вот пара служебных методов, которые могут обрабатывать вызовы методов класса и экземпляра, передаваемые как строки, с необязательными аргументами и переменными.

Это НЕ производственный код. Кажется, работает, по крайней мере, с этими тривиальными примерами.

class Program
{
    static void Main(string[] args)
    {
        double alpha = Math.Sin(1.0);
        int beta = alpha.CompareTo(1.0);
        Console.WriteLine("{0} {1}", alpha, beta);

        double gamma = (double)CallClassMethod("System.Math.Sin", 1.0);
        int delta = (int)CallInstanceMethod(gamma, "CompareTo", 1.0);
        Console.WriteLine("{0} {1}", gamma, delta);

        string a = "abc";
        string x = "xyz";
        string r = String.Join(",", a, x);
        string s = r.Replace(",", ";");
        Console.WriteLine("{0} {1}", r, s);
        string t = (string)CallClassMethod("System.String.Join", ",", new String[] { a, x }); // Join takes varargs
        string u = (string)CallInstanceMethod(t, "Replace", ",", ";");
        Console.WriteLine("{0} {1}", t, u);
        Console.ReadKey();
    }

    static object CallClassMethod(string command, params object[] args)
    {
        Regex regex = new Regex(@"(.*)\.(\w*)");
        Match match = regex.Match(command);
        string className = match.Groups[1].Value;
        string methodName = match.Groups[2].Value;
        Type type = Type.GetType(className);
        List<Type> argTypeList = new List<Type>();
        foreach (object arg in args) { argTypeList.Add(arg.GetType()); }
        Type[] argTypes = argTypeList.ToArray();
        MethodInfo method = type.GetMethod(methodName, argTypes, null);
        return method.Invoke(null, args);
    }

    static object CallInstanceMethod(object instance, string methodName, params object[] args)
    {
        Type type = instance.GetType();
        List<Type> argTypeList = new List<Type>();
        foreach (object arg in args) { argTypeList.Add(arg.GetType()); }
        Type[] argTypes = argTypeList.ToArray();
        MethodInfo method = type.GetMethod(methodName, argTypes, null);
        return method.Invoke(instance, args);
    }
}
...