Рефлексивно исполняемый код в .Net - PullRequest
2 голосов
/ 11 июня 2009

Как вы рефлекторно или динамически выполняете код в .Net? Если XML содержит что-то внутри '[]', я хочу обрабатывать текст не как текст, а как код:

<Name>DateZero</Name><br/> <Value>DateTime.Now.AddDays(-2)</Value></p> <p><Name>DateOne</Name><br/> <Value>[DateTime.Now.AddDays(-1).ToString("MM/dd/yy")]</Value></p> <p><Name>DateTwo</Name><br/> <Value>[DateTime.Now.ToString("MM/dd/yy")]</Value>

означает, что значение для DateZero будет отображаться как «DateTime.Now.AddDays (-2)», но для следующих двух оно будет отображаться как 06/10/09 и 06/11/09.

Ответы [ 8 ]

2 голосов
/ 11 июня 2009

CS-Script сделает то, что вы ищете.

Из одного из их примеров:

Assembly assembly = CSScript.LoadMethod(
        @"public static void PrintSum(int a, int b)
          {
              Console.WriteLine((a+b));
          }");

AsmHelper script = new AsmHelper(assembly);
script.Invoke("*.PrintSum", 1, 2);

Это должно быть достаточно легко, чтобы делать то, что вы хотите. Я использую его для нашего механизма правил (только что переключенного с Boo), и он отлично подходит для динамического кода.

2 голосов
/ 11 июня 2009

Похоже, вам нужен какой-то процессор базовых правил. Есть несколько вариантов выполнения того, что вам нужно. Как упоминал Рэндольфо, вы можете использовать Reflection.Emit для генерации облегченного кода IL во время выполнения. Другой вариант, если у вас есть .NET 3.5, это использовать деревья выражений.

С появлением LINQ Microsoft пришлось добавить в .NET базовый механизм выражений, в который операторы LINQ могли бы преобразовываться во время компиляции. Однако библиотека выражений не ограничивается поддержкой LINQ, и вы должны иметь возможность написать базовый синтаксический анализатор, который превратит ваш XML в дерево выражений. Каждое дерево выражений может быть позже скомпилировано в делегат, который затем может быть вызван синхронно или асинхронно.

Вы можете найти следующую ссылку полезной, если изучите маршрут дерева выражений:

http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

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

1 голос
/ 11 июня 2009

Вы действительно хотите разрешить любой C #?
Если это так, вы можете посмотреть на этот движок сценария для C # . Имейте в виду, что возможность запуска произвольного кода является большой угрозой безопасности.

Если вы в порядке с ожиданием .NET 4.0 (в бета-версии сейчас, выпуск в конце этого года), вы можете использовать для этого DLR или Dynamic Language Runtime.

С другой стороны, если вы не хотите полагаться на .NET 4.0 и хотите ограничиться, вы можете использовать Reflection довольно просто. Если бы вы могли ограничиться, например, методами экземпляра DateTime, все было бы проще. В этом примере показано, как вызвать метод через отражение в экземпляре DateTime, для которого установлено значение NOW.

  DateTime d = DateTime.Now;
  string logicToInvoke= "Now.AddDays(12)";
  string pattern = @"^Now\.(?<methodname>\w+)\((?<argstring>[^\)]*)\)";
  RGX.Match match = RGX.Regex.Match(logicToInvoke, pattern);

  // If match not found, logic is improperly formed.
  if (!match.Success)
  {
      Console.WriteLine("The DateTime method logic is improperly formed.");
      return;
  }

  // Store method and arg 
  string methodName = (string) match.Groups["methodname"].Value;
  string argString = (string) match.Groups["argstring"].Value;

  Console.WriteLine("Invoking method '{0}' with args '{1}'...", methodName, argString);
  System.Type t= d.GetType();

  try
  {
      switch (methodName)
      {

      case "AddDays" :
          int daysToAdd = System.Int32.Parse(argString);
          DateTime result = (DateTime) t.InvokeMember (methodName,
                                          System.Reflection.BindingFlags.Public | 
                                          System.Reflection.BindingFlags.Instance  |
                                          System.Reflection.BindingFlags.InvokeMethod , 
                                          null, d, new object [] {daysToAdd});

          Console.WriteLine("Result: {0}", result.ToString("yyyy/MM/dd"));
          break;
      default:
          Console.WriteLine("unsupported method: {0}", methodName);
          break;
      }

  }
  catch (System.Exception exc1)
  {
      Console.WriteLine("Exception while invoking method: {0}", exc1);
  }

Я бы рекомендовал хранить формат значения DateTime отдельно от его значения. Формат времени («гг / мм / дд») может быть лучше указан в атрибуте, например:

<Name>DateOne</Name>
<Value format="MM/dd/yy">[Now.AddDays(-1)]</Value>
1 голос
/ 11 июня 2009

Не лучше ли вам определить набор «возможных» констант, которые вы могли бы затем анализировать в своем коде и выполнять динамически, а не просто любой бит C #, который вы получили.

1 голос
/ 11 июня 2009

Хотя я не рекомендую ваш подход вообще, вы можете делать то, что вы хотите, используя Reflection.Emit. Вот учебник .

0 голосов
/ 11 июня 2009

Если вам не нужен синтаксис C # до последней запятой, возможно, самый простой способ сделать это - использовать язык DLR, например IronPython. Google для "хостинга Ironpython", и вы найдете образцы.

0 голосов
/ 11 июня 2009

В зависимости от того, что именно вы пытаетесь сделать, некоторые компоненты Spring .NET могут оказаться полезными. взгляните на Spring .NET Expressions .

Например:

(DateTime) ExpressionEvaluator.GetValue(null, "new DateTime(1974, 8, 24)")

где "new DateTime (1974,8,24)" - ваш текст

0 голосов
/ 11 июня 2009

сначала вам нужно создать и скомпилировать класс с вашим кодом в нем, в памяти, после того, как он скомпилирован, вам нужно отразить это и вызвать метод, в котором живет ваш динамический код, метод также может вернуть значение. *

вот ссылка для начала работы Динамический код

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...