2009-10-02 2 views
4

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

как я могу сделать следующее:

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

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

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

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

Спасибо.

+0

В конце концов я отказался от кода, который я написал, чтобы сделать это в течение нескольких лет, поэтому я не буду беспокоиться о ответе. Тем не менее, вы действительно можете запустить динамически построенный код на C#. Вам не нужны никакие дополнительные инструменты - он встроен в .NET framework. –

+0

Выполнение строки, поскольку код далеко не отличается от выполнения существующего метода, выбирая имя метода. – Suamere

ответ

6

Вы можете выполнить метод по имени через 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. 
} 
4

Вы считаете, что 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

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

Пример из here

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

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

public void amethod(Action function) 
{ 
    function(); 
} 
5

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

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

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

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

  • обхода встроенной системы для вызова веб-служб и создать свой собственный веб-запрос с правильным именем в правильном месте в XML.
  • Создайте делегатов для каждого из методов в сервисе, чтобы пройти, возможно, через отражение.
+0

«Плохая практика и неуверенность» Можете ли вы объяснить, почему? Существует несколько фреймворков, которые используют эту парадигму, чтобы сделать вещи динамичными. Если это плохая практика и небезопасная, то что было бы лучше и безопасно? – DarthVader

+5

Плохая идея когда-либо выполнять произвольный код, представленный пользователями. Если это _your_ string, а вы _sure_, это ваша строка, это одно. Но лучше быть уверенным в этом. Вы говорите о совершенно новой категории дыры в безопасности здесь, сродни SQL-инъекции. Просто потому, что многие динамические программы все равно не делают это правильно. –

+0

Понял. Да, я уверен, что ... никто не может получить к нему доступ, только для внутреннего использования. Спасибо. – DarthVader

1

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

Совершенно другое решение заключается в использовании класса CSharpCodeCompiler.

0

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

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

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); 
    } 
} 
Смежные вопросы