locked
Se Puede Cargar Codigo de un Texto | VB.NET RRS feed

  • 问题

  • >Hello, World!_

    Tengo la Siguiente Pregunta:

    ¿Puedo Agregar una Linea de Codigo desde un Archivo de Texto?

    Me Explico:

    En un Archivo de Texto se encuentre el siguiente Codigo

    If TextBox1.Text = "ST.Debug=AppName" Then
       RichTextBox1.AppendText(vbCrLf & "[ST]New Command: " & TextBox1.Text)
       AppName.Show()
       TextBox1.Clear()
    End If

    y que el Programa de VB.NET ejecute este Codigo del Archivo

    ¿Se Puede?

    y si es asi ¿Hay Alguna Forma?

    y si no ¿Que es lo mas Parecido?


    • 已编辑 Urfenox 2017年4月12日 1:04 Faltaban Datos del Titulo
    2017年4月12日 1:01

答案

  • Después de meses de búsqueda, resulto ser MUY FÁCIL. Tanto que me da risa la respuesta de Alberto jksjks.

    Primero los imports

    Imports System.CodeDom
    Imports System.Reflection

    Luego, un Sub o Function con el siguiente codigo:

    Dim myProcessor As Assembly
    Dim mySupplier As New VBCodeProvider
    Dim myCompilador = mySupplier.CreateCompiler
    Dim myParam As New CodeDom.Compiler.CompilerParameters
    myParam.GenerateExecutable = False 'No quiero ejecutable
    myParam.GenerateInMemory = True 'Lo quiero en memoria
    'myParam.OutputAssembly = "" 'Por si quiero generar un simbolo
    'myParam.ReferencedAssemblies.Add("") 'No quiero referencias a a DLLs o librerias.
    Dim contenidoProcesador As String = My.Computer.FileSystem.ReadAllText("C:\archivoConCodigoEnTextoPlano.txt")
    Dim myResult As Compiler.CompilerResults = myCompilador.CompileAssemblyFromSource(myParam, contenidoProcesador)
    myProcessor = myResult.CompiledAssembly
    
    'Creo la instancia de la clase
    Dim procesadorComandos = myProcessor.CreateInstance("nombreClase")
    
    'Uso la clase y llamo al metodo, luego devuelvo lo devuelto
    Dim valorDevuelto = procesadorComandos.FuncionGenerica("parametro")
    If valorDevuelto <> Nothing Then
    	Return valorDevuelto
    Else
    	Return "La funcion de la clase no ha devuelto ningun valor."
    End If

    Y la clase en cuestión tiene un aspecto:

    Public Class nombreClase
    	Public Sub New()
    	End Sub
    
    	Public Function FuncionGenerica(ByVal parametro As String) As String
    		If parametro = "" Then
    			'Do something
    			Return ""
    		ElseIf parametro = "" Then
    			'Do something else
    			Return ""
    		Else
    			Return "No procesado."
    		End If
    	End Function
    End Class

    Y así de simple.

    El código hace un compilado que ejecuta en memoria. Un código que toma desde un archivo de texto plano. Luego crea una instancia de la clase y llama a una función dentro de esta. Al final, una variable guarda el retorno de la función. Y ya está. (Muy tarde)


    --- Cristopher Cáceres | Hola! | Worcome Studios ---

    • 已标记为答案 Urfenox 2022年6月1日 17:40
    2022年6月1日 17:40

全部回复

  • Sí, se puede pero no es muy sencillo. Puedes invocar al compilador de VB.NET, que se expone como clase dentro del Framework, y entre los varios parámetros que se le pueden pasar hay uno que se llama CompileInMemory, que te devuelve un objeto con el código que ha compilado. Ese objeto después puedes invocarlo por reflexión. El efecto neto es que lo que había en el archivo se ejecuta en memoria después de tomar los pasos anteriores.

    Se complicará un poco porque es necesario que lo que tomas del archivo sea algo que compile correctamente, por lo que no pueden ser unas líneas de código "sueltas", sino que hay que meterlas dentro de un método dentro de una clase. Esto puedes hacerlo concatenando esas "piezas" alrededor de las líneas leídas del fichero. Y si en el código cargado necesitas acceder a algo externo, como por ejemplo el textBox1 que hay en el fragmento que pegaste, entonces esos datos hay que pasárselo como argumento al encapsulado que añadiste, en el momento de invocarlo por reflexión.

    Si eso lo tienes que hacer repetidamente cargando sobre la marcha muchos fragmentos de muchos archivos que van cambiando, se presenta otro problema adicional: cada vez que compilas uno y lo cargas en memoria, se genera un nuevo ensamblado, que nunca se descarga de la memoria salvo que se descargue el AppDomain que lo contiene. Por eso, si vas a cargar muchos, conviene que los cargues en un AppDomain separado, para poderlo descargar. Esto complica la llamada por Reflexión, que tiene que hacer un salto entre AppDomains y requiere encapsular los argumentos en una clase que admita al Marshalling entre AppDomains.

    Todas estas cosas funcionan muy bien una vez que las tienes escritas, pero como ves son varios temas de una complejidad considerable y que tendrías que estudiar, no es un tema trivial que se resuelva con dos líneas de código.

    2017年4月12日 5:52
  • Después de meses de búsqueda, resulto ser MUY FÁCIL. Tanto que me da risa la respuesta de Alberto jksjks.

    Primero los imports

    Imports System.CodeDom
    Imports System.Reflection

    Luego, un Sub o Function con el siguiente codigo:

    Dim myProcessor As Assembly
    Dim mySupplier As New VBCodeProvider
    Dim myCompilador = mySupplier.CreateCompiler
    Dim myParam As New CodeDom.Compiler.CompilerParameters
    myParam.GenerateExecutable = False 'No quiero ejecutable
    myParam.GenerateInMemory = True 'Lo quiero en memoria
    'myParam.OutputAssembly = "" 'Por si quiero generar un simbolo
    'myParam.ReferencedAssemblies.Add("") 'No quiero referencias a a DLLs o librerias.
    Dim contenidoProcesador As String = My.Computer.FileSystem.ReadAllText("C:\archivoConCodigoEnTextoPlano.txt")
    Dim myResult As Compiler.CompilerResults = myCompilador.CompileAssemblyFromSource(myParam, contenidoProcesador)
    myProcessor = myResult.CompiledAssembly
    
    'Creo la instancia de la clase
    Dim procesadorComandos = myProcessor.CreateInstance("nombreClase")
    
    'Uso la clase y llamo al metodo, luego devuelvo lo devuelto
    Dim valorDevuelto = procesadorComandos.FuncionGenerica("parametro")
    If valorDevuelto <> Nothing Then
    	Return valorDevuelto
    Else
    	Return "La funcion de la clase no ha devuelto ningun valor."
    End If

    Y la clase en cuestión tiene un aspecto:

    Public Class nombreClase
    	Public Sub New()
    	End Sub
    
    	Public Function FuncionGenerica(ByVal parametro As String) As String
    		If parametro = "" Then
    			'Do something
    			Return ""
    		ElseIf parametro = "" Then
    			'Do something else
    			Return ""
    		Else
    			Return "No procesado."
    		End If
    	End Function
    End Class

    Y así de simple.

    El código hace un compilado que ejecuta en memoria. Un código que toma desde un archivo de texto plano. Luego crea una instancia de la clase y llama a una función dentro de esta. Al final, una variable guarda el retorno de la función. Y ya está. (Muy tarde)


    --- Cristopher Cáceres | Hola! | Worcome Studios ---

    • 已标记为答案 Urfenox 2022年6月1日 17:40
    2022年6月1日 17:40