Como posso avaliar código C # dinamicamente?

votos
75

Eu posso fazer um eval(something());para executar o código dinamicamente em JavaScript. Existe uma maneira para eu fazer a mesma coisa em C #?

Um exemplo do que estou tentando fazer é: Eu tenho uma variável inteira (digamos i) e eu tenho várias propriedades pelos nomes: Property1, Property2, property3, etc. Agora, eu quero executar algumas operações na propriedade i propriedade, dependendo do valor de i.

Isto é realmente simples com Javascript. Existe alguma maneira de fazer isso com C #?

Publicado 07/08/2008 em 13:26
fonte usuário
Em outras línguas...                            


16 respostas

votos
41

Infelizmente, C # não é uma linguagem dinâmica como essa.

O que você pode fazer, no entanto, é criar um arquivo de código # fonte C, completo com classe e tudo, e executá-lo através do provedor CodeDom para C # e compilá-lo em uma montagem, e depois executá-lo.

Este post fórum sobre MSDN contém uma resposta com alguns exemplo de código para baixo a página um pouco:
criar um método anônimo de uma string?

Eu quase diria que esta é uma solução muito boa, mas é possível de qualquer maneira.

Que tipo de código que você vai esperar em que seqüência? Se é um subconjunto menor de código válido, por exemplo, apenas expressões matemáticas, pode ser que outras alternativas existem.


Editar : Bem, isso me ensina a ler as perguntas completamente primeiro. Sim, reflexão seria capaz de lhe dar alguma ajuda aqui.

Se você dividir a string pelo; em primeiro lugar, para obter propriedades individuais, você pode usar o seguinte código para obter um objeto PropertyInfo para uma propriedade particular, para uma classe, e em seguida, usar esse objeto para manipular um objeto particular.

String propName = "Text";
PropertyInfo pi = someObject.GetType().GetProperty(propName);
pi.SetValue(someObject, "New Value", new Object[0]);

Link: Método PropertyInfo.SetValue

Respondeu 07/08/2008 em 13:31
fonte usuário

votos
14

Na verdade não. Você pode usar o reflexo para conseguir o que deseja, mas não será tão simples como em Javascript. Por exemplo, se você queria para definir o campo privado de um objeto para alguma coisa, você poderia usar esta função:

protected static void SetField(object o, string fieldName, object value)
{
   FieldInfo field = o.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);
   field.SetValue(o, value);
}
Respondeu 07/08/2008 em 13:31
fonte usuário

votos
10

Usando a API Roslyn scripting (mais amostras aqui ):

// add NuGet package 'Microsoft.CodeAnalysis.Scripting'
using Microsoft.CodeAnalysis.CSharp.Scripting;

await CSharpScript.EvaluateAsync("System.Math.Pow(2, 4)") // returns 16

Você também pode executar qualquer parte do código:

var script = await CSharpScript.RunAsync(@"
                class MyClass
                { 
                    public void Print() => System.Console.WriteLine(1);
                }")

E fazer referência ao código que foi gerado em execuções anteriores:

await script.ContinueWithAsync("new MyClass().Print();");
Respondeu 23/06/2016 em 06:33
fonte usuário

votos
7

Eu escrevi um projeto de código aberto, dinâmico Expresso , que pode converter expressão de texto escrito usando um # sintaxe C em delegados (ou árvore de expressão). Expressões são analisados e transformados em árvores de expressão sem usar compilação ou reflexão.

Você pode escrever algo como:

var interpreter = new Interpreter();
var result = interpreter.Eval("8 / 2 + 2");

ou

var interpreter = new Interpreter()
                      .SetVariable("service", new ServiceExample());

string expression = "x > 4 ? service.SomeMethod() : service.AnotherMethod()";

Lambda parsedExpression = interpreter.Parse(expression, 
                          new Parameter("x", typeof(int)));

parsedExpression.Invoke(5);

Meu trabalho é baseado no artigo Scott Gu http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx .

Respondeu 03/02/2013 em 10:29
fonte usuário

votos
7

Esta é uma função eval em c #. Usei-o para converter funções anônimas (Lambda expressões) a partir de uma string. Fonte: http://www.codeproject.com/KB/cs/evalcscode.aspx

public static object Eval(string sCSCode) {

  CSharpCodeProvider c = new CSharpCodeProvider();
  ICodeCompiler icc = c.CreateCompiler();
  CompilerParameters cp = new CompilerParameters();

  cp.ReferencedAssemblies.Add("system.dll");
  cp.ReferencedAssemblies.Add("system.xml.dll");
  cp.ReferencedAssemblies.Add("system.data.dll");
  cp.ReferencedAssemblies.Add("system.windows.forms.dll");
  cp.ReferencedAssemblies.Add("system.drawing.dll");

  cp.CompilerOptions = "/t:library";
  cp.GenerateInMemory = true;

  StringBuilder sb = new StringBuilder("");
  sb.Append("using System;\n" );
  sb.Append("using System.Xml;\n");
  sb.Append("using System.Data;\n");
  sb.Append("using System.Data.SqlClient;\n");
  sb.Append("using System.Windows.Forms;\n");
  sb.Append("using System.Drawing;\n");

  sb.Append("namespace CSCodeEvaler{ \n");
  sb.Append("public class CSCodeEvaler{ \n");
  sb.Append("public object EvalCode(){\n");
  sb.Append("return "+sCSCode+"; \n");
  sb.Append("} \n");
  sb.Append("} \n");
  sb.Append("}\n");

  CompilerResults cr = icc.CompileAssemblyFromSource(cp, sb.ToString());
  if( cr.Errors.Count > 0 ){
      MessageBox.Show("ERROR: " + cr.Errors[0].ErrorText, 
         "Error evaluating cs code", MessageBoxButtons.OK, 
         MessageBoxIcon.Error );
      return null;
  }

  System.Reflection.Assembly a = cr.CompiledAssembly;
  object o = a.CreateInstance("CSCodeEvaler.CSCodeEvaler");

  Type t = o.GetType();
  MethodInfo mi = t.GetMethod("EvalCode");

  object s = mi.Invoke(o, null);
  return s;

}
Respondeu 23/06/2011 em 17:25
fonte usuário

votos
7

Tudo isso com certeza gostaria de trabalhar. Pessoalmente, para esse problema específico, eu provavelmente iria demorar um pouco abordagem diferente. Talvez algo como isto:

class MyClass {
  public Point point1, point2, point3;

  private Point[] points;

  public MyClass() {
    //...
    this.points = new Point[] {point1, point2, point3};
  }

  public void DoSomethingWith(int i) {
    Point target = this.points[i+1];
    // do stuff to target
  }
}

Ao usar padrões como este, você tem que ter cuidado para que seus dados são armazenados por referência e não por valor. Em outras palavras, não faça isso com primitivos. Você tem que usar suas grandes contrapartes classe inchado.

Percebi que não é exatamente a questão, mas a questão foi muito bem respondida e eu pensei que talvez uma abordagem alternativa pode ajudar.

Respondeu 07/08/2008 em 13:47
fonte usuário

votos
5

Eu não faço agora se você absolutamente deseja executar C # declarações, mas você já pode executar instruções de JavaScript em C # 2.0. A biblioteca de código aberto Jint é capaz de fazê-lo. É um interpretador Javascript para .NET. Passe um programa Javascript e ele será executado dentro de sua aplicação. Você pode até passar C # objeto como argumentos e fazer a automação nele.

Além disso, se você quiser apenas para avaliar a expressão em suas propriedades, dar uma chance para NCalc .

Respondeu 14/10/2009 em 09:06
fonte usuário

votos
3

Você pode usar a reflexão para obter a propriedade e invocá-lo. Algo assim:

object result = theObject.GetType().GetProperty("Property" + i).GetValue(theObject, null);

Ou seja, supondo que o objeto que tem a propriedade é chamado de "theObject" :)

Respondeu 07/08/2008 em 13:29
fonte usuário

votos
1

Você também pode implementar um Webbrowser, em seguida, carregar um wich arquivo html contém javascript.

Então u ir para o document.InvokeScriptMétodo neste browser. O valor de retorno da função eval pode ser catched e convertido em tudo que você precisa.

Eu fiz isso em vários projectos e ele funciona perfeitamente.

Espero que ajude

Respondeu 01/10/2010 em 18:03
fonte usuário

votos
0

Você pode verificar o Heleonix.Reflection biblioteca. Ele fornece métodos para obter / set / chamar membros de forma dinâmica, incluindo membros aninhados, ou se um membro está claramente definido, você pode criar um getter / setter (lambda compilado em um delegado) que é mais rápido do que a reflexão:

var success = Reflector.Set(instance, null, $"Property{i}", value);

Ou se o número de propriedades não é infinita, você pode gerar setters e Chache eles (setters são mais rápidos, uma vez que são compilados delegados):

var setter = Reflector.CreateSetter<object, object>($"Property{i}", typeof(type which contains "Property"+i));
setter(instance, value);

Setters pode ser do tipo Action<object, object>, mas instâncias podem ser diferentes em tempo de execução, de modo que você pode criar listas de setters.

Respondeu 13/07/2018 em 10:04
fonte usuário

votos
0

Eu estava tentando obter um valor de um (classe) membro da estrutura por ele é nome. A estrutura não foi dinâmica. Todas as respostas não funcionou até que eu finalmente consegui-lo:

public static object GetPropertyValue(object instance, string memberName)
{
    return instance.GetType().GetField(memberName).GetValue(instance);
}

Este método irá retornar o valor do membro por ele é nome. Ele funciona em estrutura regular (classe).

Respondeu 02/05/2018 em 13:56
fonte usuário

votos
0

Eu escrevi um pacote, SharpByte.Dynamic , para simplificar a tarefa de compilar e executar o código de forma dinâmica. O código pode ser chamado em qualquer objeto de contexto usando métodos de extensão, conforme detalhado mais aqui .

Por exemplo,

someObject.Evaluate<int>("6 / {`0`}", 3))

retorna 3;

someObject.Evaluate("this.ToString()"))

retorna representação string do objeto de contexto;

someObject.Execute(@
"Console.WriteLine(""Hello, world!"");
Console.WriteLine(""This demonstrates running a simple script"");
");

executa essas declarações como um script, etc.

Executáveis pode ser obtido facilmente utilizando um método de fábrica, como se vê no exemplo aqui --all que você precisa é o código fonte e lista de quaisquer parâmetros nomeados esperados (tokens são incorporados usando a notação de triplo-suporte, como { `0`}, para evitar colisões com string.Format () bem como sintaxes guiador e similares):

IExecutable executable = ExecutableFactory.Default.GetExecutable(executableType, sourceCode, parameterNames, addedNamespaces);

Cada objeto executável (script ou expressão) é thread-safe, podem ser armazenados e reutilizados, suporta o registo a partir de um roteiro, armazena informações e última exceção sincronismo se encontrou, etc. Há também uma cópia (método) compilado em cada para permitir a criação de cópias baratas, ou seja, utilizando um objecto executável compilado a partir de um script ou expressão como um molde para a criação de outros.

Sobrecarga de executar um script já compilado ou declaração é relativamente baixo, em bem menos de um microssegundo em hardware modesto e scripts e expressões já compilados são armazenados em cache para reutilização.

Respondeu 14/08/2017 em 11:28
fonte usuário

votos
0

Usa reflexão para analisar e avaliar uma expressão de ligação de dados contra um objeto em tempo de execução.

Método DataBinder.Eval

Respondeu 05/11/2011 em 15:40
fonte usuário

votos
0

Você poderia fazê-lo com uma função protótipo:

void something(int i, string P1) {
    something(i, P1, String.Empty);
}

void something(int i, string P1, string P2) {
    something(i, P1, P2, String.Empty);
}

void something(int i, string P1, string P2, string P3) {
    something(i, P1, P2, P3, String.Empty);
}

e assim por diante...

Respondeu 07/08/2008 em 13:30
fonte usuário

votos
-1

Infelizmente, C # não tem nenhum instalações nativas para fazer exatamente o que você está pedindo.

No entanto, o meu programa # eval C não permite a avaliação de código C #. Ele fornece para avaliar código C # em tempo de execução e suporta muitas declarações C #. Na verdade, este código é utilizável em qualquer projeto .NET, no entanto, é limitada ao uso de C # sintaxe. Dê uma olhada no meu site, http://csharp-eval.com , para obter detalhes adicionais.

Respondeu 10/06/2011 em 03:24
fonte usuário

votos
-8

a resposta correta é que você precisa para armazenar em cache todo o resultado para manter o baixo uso mem0ry.

um exemplo seria algo como isto

TypeOf(Evaluate)
{
"1+1":2;
"1+2":3;
"1+3":5;
....
"2-5":-3;
"0+0":1
} 

e adicionar a uma lista

List<string> results = new List<string>();
for() results.Add(result);

salvar o id e usá-lo no código

espero que isto ajude

Respondeu 26/08/2011 em 13:37
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more