<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>il libero &#187; Mono/.NET</title>
	<atom:link href="http://www.miltonpividori.com.ar/category/software/mononet/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.miltonpividori.com.ar</link>
	<description>Blog de Milton Pividori</description>
	<lastBuildDate>Mon, 02 Jan 2012 04:12:27 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Gtk+: trabajando con TreeViews</title>
		<link>http://www.miltonpividori.com.ar/2009/06/22/gtk-trabajando-con-treeviews/</link>
		<comments>http://www.miltonpividori.com.ar/2009/06/22/gtk-trabajando-con-treeviews/#comments</comments>
		<pubDate>Mon, 22 Jun 2009 13:32:47 +0000</pubDate>
		<dc:creator>miltondp</dc:creator>
				<category><![CDATA[Facultad]]></category>
		<category><![CDATA[GNOME]]></category>
		<category><![CDATA[Mono/.NET]]></category>
		<category><![CDATA[Proyectos]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Software Libre]]></category>

		<guid isPermaLink="false">http://www.miltonpividori.com.ar/?p=668</guid>
		<description><![CDATA[Este post puede ser útil para los que utilicen el widget TreeView de Gtk+ (no importa el lenguaje mientras haya bindings), y necesiten activar por código celdas en modo edición. Hay algunas cuestiones a tener en cuenta. Para el Proyecto Final de Carrera estamos desarrollando un sistema de nivel operativo, con funciones de facturación y [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.miltonpividori.com.ar/wp-content/uploads/2009/06/edicion-treeview1.png" alt="edicion-treeview1" title="edicion-treeview1" width="186" height="69" class="alignright size-full wp-image-685" /></p>
<p>Este post puede ser útil para los que utilicen el widget <a href="http://library.gnome.org/devel/gtk/unstable/GtkTreeView.html">TreeView</a> de <a href="http://www.gtk.org/">Gtk+</a> (no importa el lenguaje mientras haya bindings), y necesiten activar por código celdas en modo edición. Hay algunas cuestiones a tener en cuenta.</p>
<p>Para el Proyecto Final de Carrera estamos desarrollando un sistema de nivel operativo, con funciones de facturación y demás. Necesitamos manejar un TreeView con campos editables, y al finalizar la edición de uno de ellos es necesario dar el foco a otro campo en modo edición, listo para que el usuario comience a cargar datos sin tocar el mouse.</p>
<p><span id="more-668"></span><br />
Lo primero que hicimos fue conectar un método al evento <a href="http://library.gnome.org/devel/gtk/unstable/GtkCellRendererText.html#GtkCellRendererText-edited">Edited</a> del <a href="http://library.gnome.org/devel/gtk/unstable/GtkCellRendererText.html">CellRendererText</a> de la columna correspondiente. De esta forma, cuando terminamos la edición en el primer campo, podemos colocar allí el código correspondiente para actualizar el modelo del TreeView y otras operaciones más, entre ellas (la que nos interesa) dar el foco al segundo campo en modo edición. La parte final de este método (el evento se activa al finalizar la edición) había quedado así:</p>
<pre class="brush: csharp; title: ; notranslate">
/* ... */

this.tvItems.SetCursor(path,
					   this.tvcCodigoProducto,
					   true);
</pre>
<p>Hay que tener cuidado al utilizar la función <a href="http://library.gnome.org/devel/gtk/unstable/GtkTreeView.html#gtk-tree-view-set-cursor">SetCursor</a>. En algunos casos, si no la usamos cuidadosamente, el TreeView no se comportará en forma correcta. Esos casos son por ejemplo cuando el usuario, al estar editando el campo, hace click en otra fila. Esto hace que se dispare el evento <em>Edited</em>, y por lo tanto se activa el modo edición en el segundo campo (SetCursor), pero el foco lo tiene otra fila, y esto hace que el funcionamiento sea incorrecto.</p>
<p>La solución es, antes de ejecutar SetCursor, verificar qué tipo de evento ha ocurrido. En nuestro caso, ejecutamos dicha función sólo si se ha oprimido la tecla <em>Return</em>. El código queda así:</p>
<pre class="brush: csharp; title: ; notranslate">
/* Una vez editada la cantidad, automáticamente
 * pasamos el foco al campo de 'código' en modo
 * edición, pero en una nueva fila. A esto lo hacemos
 * únicamente si el usuario presionó la tecla Enter */

Gdk.Event ev = Gtk.Application.CurrentEvent;

if (ev.Type == Gdk.EventType.KeyPress) {
	Gdk.EventKey evKey = (Gdk.EventKey)ev;

	if (evKey.Key == Gdk.Key.Return)
		this.tvItems.SetCursor(path,
							   this.tvcCodigoProducto,
							   true);
}
</pre>
<p>Lo cual es más lógico también: si se hace click en otra fila, seguramente es porque se quiere editar otro ítem y por lo tanto no es correcto forzar el foco en otro lugar. Además, como se dijo, esto hacía que el TreeView quede en un estado inconsistente.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.miltonpividori.com.ar/2009/06/22/gtk-trabajando-con-treeviews/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Mono C# Shell</title>
		<link>http://www.miltonpividori.com.ar/2009/02/12/mono-c-shell/</link>
		<comments>http://www.miltonpividori.com.ar/2009/02/12/mono-c-shell/#comments</comments>
		<pubDate>Thu, 12 Feb 2009 18:41:42 +0000</pubDate>
		<dc:creator>miltondp</dc:creator>
				<category><![CDATA[Mono/.NET]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Software Libre]]></category>

		<guid isPermaLink="false">http://www.miltonpividori.com.ar/?p=593</guid>
		<description><![CDATA[El otro día necesitaba saber bien cómo funcionaba el método Remove de la clase StringBuilder en Mono. Entonces hice lo siguiente: Si, funcionaba como me lo imaginaba Esta shell para C# está disponible en la versión 2.2 de Mono.]]></description>
			<content:encoded><![CDATA[<p>El otro día necesitaba saber bien cómo funcionaba el método <em>Remove</em> de la clase <em>StringBuilder</em> en Mono. Entonces hice lo siguiente:</p>
<pre class="brush: plain; title: ; notranslate">
miltondp@wasabi:~$ csharp
Mono C# Shell, type &quot;help;&quot; for help

Enter statements below.
csharp&gt; using System.Text;
csharp&gt; var a = new StringBuilder(&quot;Milton&quot;);
csharp&gt; a.Remove(a.Length-1,1);
Milto
csharp&gt; a.Remove(a.Length-1,1);
Milt
csharp&gt; a.Remove(a.Length-1,1);
Mil
csharp&gt; a.Remove(a.Length-1,1);
Mi
csharp&gt; a.Remove(a.Length-1,1);
M
csharp&gt; a.Remove(a.Length-1,1); 

csharp&gt;
</pre>
<p>Si, funcionaba como me lo imaginaba <img src='http://www.miltonpividori.com.ar/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  Esta shell para C# está disponible en la versión 2.2 de Mono.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.miltonpividori.com.ar/2009/02/12/mono-c-shell/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Zaspe# 0.1.0 released!</title>
		<link>http://www.miltonpividori.com.ar/2008/07/17/zaspe-010-released/</link>
		<comments>http://www.miltonpividori.com.ar/2008/07/17/zaspe-010-released/#comments</comments>
		<pubDate>Fri, 18 Jul 2008 01:22:40 +0000</pubDate>
		<dc:creator>miltondp</dc:creator>
				<category><![CDATA[Mono/.NET]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Software Libre]]></category>
		<category><![CDATA[ZaspeSharp]]></category>

		<guid isPermaLink="false">http://www.miltonpividori.com.ar/?p=218</guid>
		<description><![CDATA[Estos días me hice un tiempo para publicar una versión un poco más usable de Zaspe#: ahora es posible generar reportes. Sin embargo la funcionalidad no es todavía muy configurable. Hay muchas mejoras que se pueden hacer, pero eso llevará tiempo. Los reportes que se pueden realizar son de personas y asistencias (aquí y aquí [...]]]></description>
			<content:encoded><![CDATA[<p>Estos días me hice un tiempo para publicar una versión un poco más usable de <a href="http://zaspe-sharp.googlecode.com/">Zaspe#</a>: ahora es posible generar reportes. Sin embargo la funcionalidad no es todavía muy configurable. Hay muchas mejoras que se pueden hacer, pero eso llevará tiempo.</p>
<p>Los reportes que se pueden realizar son de personas y asistencias (<a href='http://www.miltonpividori.com.ar/wp-content/uploads/2008/07/lista_asistencias.pdf'>aquí</a> y <a href='http://www.miltonpividori.com.ar/wp-content/uploads/2008/07/lista_personas.pdf'>aquí</a> tienen ejemplos). Éstos se producen en formato PDF. Lamentablemente no hay una forma de imprimir los reportes directamente, por lo que puede ser complicado para usuarios inexpertos.</p>
<p>Al final, estoy utilizando <a href="http://itextsharp.sourceforge.net/">iTextSharp</a> para generar los PDFs, no MonoReporter, que si bien actualmente puede generar reportes básicos, decidí por el momento utilizar algo ya hecho y maduro. Con MonoReporter (que utiliza GtkPrint) sí podría imprimir el reporte directamente, o ver previsualizaciones. Pero bueno, será algo a hacer más adelante.</p>
<p><span id="more-218"></span><br />
Para realizar reportes más personalizados, tengo pensando añadir a Zaspe# posibilidades de extensión, con <a href="http://www.mono-project.com/Mono.Addins">Mono.Addins</a>. Estaría bueno poder definirlos en un lenguaje tipo Boo (ya que los reportes con iTextSharp habría que diseñarlos con código fuente, nada gráfico), de sintaxis parecida a Python, y sin la necesidad de compilar el código. Así sería muy fácil incluso añadir funcionalidad en forma de plugin.</p>
<p>En la wiki hay una <a href="http://code.google.com/p/zaspe-sharp/wiki/TODO">página TODO</a> donde voy anotando las características que me gustaría añadir más adelante.</p>
<p>Un screenshot simple del diálogo para generar los reportes:</p>
<p><img src="http://www.miltonpividori.com.ar/wp-content/uploads/2008/07/dialogo_generar_reporte.png" alt="" title="dialogo_generar_reporte" width="475" height="481" class="aligncenter size-full wp-image-222" /></p>
<p>Si, muy simple y limitado.</p>
<p>En los releases anteriores, nunca subía el código fuente de la versión, aunque sí hacía un copia de la revisión en &#8216;trunk&#8217; correspondiente a la versión liberada en la carpeta &#8216;tags&#8217;. Esta vez <a href="http://code.google.com/p/zaspe-sharp/downloads/list">pueden bajarse</a> en un archivo comprimido los binarios y los fuentes.</p>
<p>Hay algunas cuestiones a tener en cuenta con respecto a la versión de Gtk# en Windows, que se pueden leer en el archivo README de los binarios. En GNU/Linux funciona bien en Ubuntu Hardy Heron con Gtk# 2.12.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.miltonpividori.com.ar/2008/07/17/zaspe-010-released/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Un servidor web en 30 líneas de código</title>
		<link>http://www.miltonpividori.com.ar/2008/03/30/un-servidor-web-en-30-lineas-de-codigo/</link>
		<comments>http://www.miltonpividori.com.ar/2008/03/30/un-servidor-web-en-30-lineas-de-codigo/#comments</comments>
		<pubDate>Mon, 31 Mar 2008 02:48:40 +0000</pubDate>
		<dc:creator>miltondp</dc:creator>
				<category><![CDATA[Mono/.NET]]></category>
		<category><![CDATA[Software]]></category>

		<guid isPermaLink="false">http://www.miltonpividori.com.ar/2008/03/30/un-servidor-web-en-30-lineas-de-codigo/</guid>
		<description><![CDATA[Interesante este post de Oren Eini. Es un código escrito en Boo (lenguaje tipo Python para .NET): import System.Net import System.IO if argv.Length != 2: print "You must pass [prefix] [path] as parameters" return prefix = argv[0] path = argv[1] if not Directory.Exists(path): print "Could not find ${path}" return listener = HttpListener() listener.Prefixes.Add(prefix) listener.Start() while [...]]]></description>
			<content:encoded><![CDATA[<p>Interesante <a href="http://ayende.com/Blog/archive/2008/03/30/A-web-server-in-30-lines-of-code.aspx">este post</a> de <a href="http://ayende.com/Blog/Default.aspx">Oren Eini</a>. Es un código escrito en <a href="http://boo.codehaus.org/">Boo</a> (lenguaje tipo Python para .NET):</p>
<pre lang="python">
import System.Net
import System.IO

if argv.Length != 2:
	print "You must pass [prefix] [path] as parameters"
	return

prefix = argv[0]
path = argv[1]

if not Directory.Exists(path):
	print "Could not find ${path}"
	return

listener = HttpListener()
listener.Prefixes.Add(prefix)
listener.Start()

while true:
	context = listener.GetContext()
	file = Path.GetFileName(context.Request.RawUrl)
	fullPath = Path.Combine(path, file)
	if File.Exists(fullPath):
		context.Response.AddHeader("Content-Disposition","attachment; filename=${file}")
		bytes = File.ReadAllBytes(fullPath)
		context.Response.OutputStream.Write(bytes, 0, bytes.Length)
		context.Response.OutputStream.Flush()
		context.Response.Close()
	else:
		context.Response.StatusCode = 404
		context.Response.Close()
</pre>
<p>Y ejecutando el comando:</p>
<pre>
$ booi prueba.boo http://localhost:8085/ ~/Escritorio/
</pre>
<p>tenemos funcionando un webserver localmente. Me acuerdo como en una de las charlas de alguna de las jornadas Python en Santa Fe el disertante hacía algo similar. La verdad, muy útil este tipo de código.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.miltonpividori.com.ar/2008/03/30/un-servidor-web-en-30-lineas-de-codigo/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>MockObjects con Rhino.Mocks</title>
		<link>http://www.miltonpividori.com.ar/2008/02/06/mockobjects-con-rhinomocks/</link>
		<comments>http://www.miltonpividori.com.ar/2008/02/06/mockobjects-con-rhinomocks/#comments</comments>
		<pubDate>Wed, 06 Feb 2008 18:15:33 +0000</pubDate>
		<dc:creator>miltondp</dc:creator>
				<category><![CDATA[Mono/.NET]]></category>
		<category><![CDATA[Software]]></category>

		<guid isPermaLink="false">http://www.miltonpividori.com.ar/?p=188</guid>
		<description><![CDATA[Cuando escribimos tests de unidad, intentamos testear una única funcionalidad. Esto muchas veces es bastante difícil, ya que generalmente necesitamos apoyarnos en otras clases distintas para cumplir con el propósito de la testeada, y terminamos probando, al final, otras cosas. Y si fallan estas clases &#8220;base&#8221;, a veces es difícil rastrear cuál es el error. [...]]]></description>
			<content:encoded><![CDATA[<p>Cuando escribimos tests de unidad, intentamos testear una única funcionalidad. Esto muchas veces es bastante difícil, ya que generalmente necesitamos apoyarnos en otras clases distintas para cumplir con el propósito de la testeada, y terminamos probando, al final, otras cosas. Y si fallan estas clases &#8220;base&#8221;, a veces es difícil rastrear cuál es el error.</p>
<p>Por ejemplo, supongamos que tenga un método <em>RegistrarAsistencia(int, int)</em>, que registra que la persona asistió al evento (los argumentos serían los IDs). Este método inventado, tendría como dependencia la clase ControladorPersonas y ControladorEventos, para levantar los objetos necesarios y realizar el registro. Pero esto (levantar los objetos Persona y Registro), a nosotros, no nos interesa probar en el test de unidad, sino verificar que el método <em>RegistrarAsistencia</em> realmente funciona, registrando que la persona asistió al evento.</p>
<p>Otro ejemplo podría ser algún método <em>ImprimirFactura</em>, que toma los datos del formulario, e imprime la factura. ¿Cómo podemos escribir un test de unidad para esto?</p>
<p>Una solución viene de la mano de la técnica de MockObjects, y Rhino.Mocks es un framework para .NET.</p>
<p><span id="more-188"></span><br />
Para el caso del método <em>RegistrarAsistencia</em>, podríamos crear objetos mock que simulen a los respectivos controladores, e indicarles a los mismos que cuando sean llamados con determinados argumentos, retornen determinados objetos. De esta forma, la lógica del método a probar siempre obtendrá resultados de los controladores, no hay que preparar la base de datos, y obtenemos un comportamiento determinístico.</p>
<p>Necesitamos manejarnos con interfaces. Así, para el controlador de personas, habrá una interfaz IControladorPersonas que éste implementará. Así podemos escribir un test de unidad utilizando Rhino.Mocks de la siguiente forma:</p>
<pre lang="csharp">
[Test]
public void RegistrarAsistencia()
{
	IControladorPersonas cp = this.mocks.CreateMock<IControladorPersonas>();
	Expect.Call(cp.ObtenerPersona(38))
		.Return(new Persona("Pividori", "Milton"));
	ControladorPersonas.Instancia = cp;

	IControladorEventos ce = this.mocks.CreateMock<IControladorEventos>();
	Expect.Call(ce.ObtenerEvento(11))
		.Return(new Evento(new DateTime(1, 1, 2000)));
	ControladorEventos.Instancia = ce;

	ISession session = this.mocks.CreateMock<ISession>();
		Expect.Call(session.Save(1))
			.Return(null)
			.IgnoreArguments();
		Expect.Call(session.Close());

	this.mocks.ReplayAll();

	Asistencia asistencia = controladorAsistencias.RegistrarAsistencia(session, 38, 11);
	Assert.AreEqual("Pividori", asistencia.Persona.Apellido);
	Assert.AreEqual(new DateTime(1, 1, 2000), asistencia.Event.Fecha);

	this.mocks.VerifyAll();
}
</pre>
<p>El objeto <em>this.mocks</em> es de tipo MockRepository, y lo utilizamos para crear nuestros objetos mock. En la primera línea estamos creando un objeto simulado (mock) que implementará la interfaz IControladorPersonas. Luego lo configuramos para que al ejecutarse en el mismo el método ObtenerPersona con el argumento &#8220;38&#8243;, éste devuelva el objeto Persona que creamos allí. Como RegistrarAsistencia utilizará la propiedad estática Instancia para obtener el controlador que necesita, guardamos en éste el objeto mock que acabamos de crear.</p>
<p>Al crear el objeto simulado con el método CreateMock, estamos diciéndole a Rhino.Mocks que verifique estrictamente la llamada a los métodos que definimos. En este caso no tiene mucho sentido porque se llama un sólo método, pero al ser varios, el test fallará si los mismos no se llaman en orden, o incluso si se llama otro que no hayamos definido. Hay otras opciones, como DynamicMock que exige que se llamen todos los métodos definidos, pero no en orden estricto, y si se llama a uno no definido retornará 0 o null, según corresponda.</p>
<p>Luego de configurar el objeto IControladorEventos, creamos un objeto de tipo ISession (de NHibernate), que pasamos al método RegistrarAsistencia para que utilice. Grabamos los métodos &#8220;Save&#8221; y &#8220;Close&#8221;, que deberán llamarse en ese orden.</p>
<p>Al terminar la fase de configuración, pasamos a la ejecución llamando <em>this.mocks.ReplayAll()</em>. Aquí ejecutamos el método por probar. Luego verificamos los resultados con NUnit. Finalmente llamamos a VerifyAll para verificar que la ejecución se halla llevado a cabo según nuestra configuración.</p>
<p>Para el otro caso, <em>ImprimirFactura</em>, podemos utilizar algo similar. Supongamos que tenemos una clase que se encarga de las funciones de la impresora. Podríamos crear una interfaz, configurar los métodos necesarios, y correr los test todas las veces que quieramos para verificar que el método funciona, aislando en el test de unidad sólo la porción de código que nos interesa probar.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.miltonpividori.com.ar/2008/02/06/mockobjects-con-rhinomocks/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Mono + NHibernate + SQLite</title>
		<link>http://www.miltonpividori.com.ar/2007/12/30/mono-nhibernate-sqlite/</link>
		<comments>http://www.miltonpividori.com.ar/2007/12/30/mono-nhibernate-sqlite/#comments</comments>
		<pubDate>Mon, 31 Dec 2007 00:11:53 +0000</pubDate>
		<dc:creator>miltondp</dc:creator>
				<category><![CDATA[Mono/.NET]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Software Libre]]></category>

		<guid isPermaLink="false">http://www.miltonpividori.com.ar/?p=185</guid>
		<description><![CDATA[Después de usar por tanto tiempo Gentle.NET, un ORM que ha sido discontinuado, he decidido al fin comenzar a estudiar NHibernate. Los ejemplos que dan en los manuales y páginas son para Windows (con MS .NET) y SQL Server. Trabajando en GNU/Linux, hice las pruebas con SQLite. El problema es que el driver utilizado por [...]]]></description>
			<content:encoded><![CDATA[<p>Después de usar por tanto tiempo <a href="http://www.mertner.com/confluence/display/Gentle/Home">Gentle.NET</a>, un ORM que ha sido discontinuado, he decidido al fin comenzar a estudiar <a href="http://www.nhibernate.org">NHibernate</a>. Los ejemplos que dan en los manuales y páginas son para Windows (con MS .NET) y SQL Server. Trabajando en GNU/Linux, hice las pruebas con <a href="http://www.sqlite.org/">SQLite</a>.</p>
<p>El problema es que el <a href="http://sourceforge.net/projects/adodotnetsqlite">driver utilizado por NHibernate</a> para esta base de datos utiliza un binding desactualizado. Además Mono trae una implementación mejor, que soporta el standard ADO.NET 2.0, que es <a href="http://www.mono-project.com/SQL_Lite">Mono.Data.Sqlite</a>, disponible <a href="http://www.go-mono.com/archive/1.2.4/">a partir de la versión 1.2.4</a>.</p>
<p>El post es especialmente útil para aquellos que quieran utilizar en GNU/Linux (yo uso Ubuntu Gutsy), con Mono, NHibernate y SQLite, utilizando el binding Mono.Data.Sqlite. Si bien puede parecer esto tan fácil como seguir el <a href="http://www.hibernate.org/362.html">documento QuickStart</a> y cambiar las opciones correspondientes, no lo es si se intenta utilizar SQLite. Por eso, en este post no voy a explicar todas las cosas, ya que no me interesa y se pueden aprender en la documentación, sino que voy a desarrollar un ejemplo muy sencillo y mostrar cómo utilizar SQLite, ya que hay que solucionar unos problemas no muy triviales.</p>
<p><span id="more-185"></span><br />
Cabe aclarar que, si bien todavía no lo he probado, los archivos de mapeo (hbm.xml) y el schema SQL se pueden autogenerar.</p>
<p>Primero creo la tabla que almacenerá los objetos en un archivo llamado, por ejemplo, <em>data.db.sql</em>:</p>
<pre lang="sql">
DROP TABLE IF EXISTS personas;

CREATE TABLE personas (
	id integer primary key,
	nombre varchar(20),
	apellido varchar(20)
);</pre>
<p>Para el ejemplo utilicé la última versión de SQLite. Para crear la base de datos en el archivo <em>data.db</em>, ejecutamos:</p>
<pre lang="bash">
$ sqlite3 data.db < data.db.sql
$
</pre>
<p>La clase de ejemplo (<em>Persona.cs</em>):</p>
<pre lang="csharp">
using System;

namespace PruebaNHibernate
{
	public class Persona
	{
		private int id;
		private string nombre;
		private string apellido;

		public Persona()
		{
		}

		public int Id {
			get { return id; }
			set { this.id = value; }
		}

		public string Nombre {
			get { return nombre; }
			set { this.nombre = value; }
		}

		public string Apellido {
			get { return apellido; }
			set { this.apellido = value; }
		}
	}
}
</pre>
<p>Luego hay que escribir el archivo de mapeo, que es un XML.</p>
<pre lang="xml">
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
	namespace="PruebaNHibernate" assembly="PruebaNHibernate">

	<class name="Persona" table="personas">
		<id name="Id" column="id" type="Int32">
			<generator class="increment" />
		</id>
<property name="Nombre" column="nombre" />
<property name="Apellido" column="apellido" />
	</class>
</hibernate-mapping>
</pre>
<p>Este archivo se debe agregar como recurso en MonoDevelop.</p>
<p>Luego escribimos el archivo de configuración para nuestra aplicación (<em>app.config</em>):</p>
<pre lang="xml">
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
	<configSections>
<section name="nhibernate"
				 type="System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0,Culture=neutral, PublicKeyToken=b77a5c561934e089" />
	</configSections>

	<nhibernate>
		<add
			key="hibernate.connection.provider"
			value="NHibernate.Connection.DriverConnectionProvider"
		/>
		<add
			key="hibernate.dialect"
			value="NHibernate.Dialect.SQLiteDialect"
		/>
		<add
			key="hibernate.connection.driver_class"
			value="PruebaNHibernate.MonoDataSqliteDriver, PruebaNHibernate"
		/>
		<add
			key="hibernate.connection.connection_string"
			value="Data Source=data.db,version=3"
		/>
		<add
			key="hibernate.query.substitutions"
			value="true=1;false=0"
		/>
		<add
			key="hibernate.use_prox y_validator"
			value="false"
		/>
	</nhibernate>
</configuration>
</pre>
<p><b>Nota:</b> Debido a problemas con el hosting no puedo colocar, arriba, el string correcto en la última parte. La palabra prohibida "p r o x y" (sin espacios) tiene un espacio de más entre la "x" y la "y". En fin, deshabilito en esas lineas la comprobación de clases p r o x y.</p>
<p>Luego en un archivo como <em>Main.cs</em> agrego código en el método principal <em>Main</em> para jugar con todo esto:</p>
<pre lang="csharp">
using System;
using NHibernate;
using NHibernate.Cfg;

namespace PruebaNHibernate
{
	class MainClass
	{
		public static void Main(string[] args)
		{
			Configuration conf = new Configuration();
			/* Con la siguiente línea leo todo los archivos con extensión
			 * hbm.xml embebidos como recurso en el assembly especificado */
			conf.AddAssembly("PruebaNHibernate");

			ISessionFactory sessionFactory = conf.BuildSessionFactory();

			ISession s = sessionFactory.OpenSession();

			ITransaction tx = s.BeginTransaction();

			Persona p = new Persona();
			p.Nombre = "Milton";
			p.Apellido = "Pividori";
			s.Save(p);
			tx.Commit();

			Console.WriteLine("p - Id: " + p.Id);
			Console.WriteLine("p - Nombre: " + p.Nombre);
			Console.WriteLine("p - Apellido: " + p.Apellido);
			Console.WriteLine();

			Persona p2 = (Persona)s.Load(typeof(Persona), p.Id);

			Console.WriteLine("p2 - Id: " + p2.Id);
			Console.WriteLine("p2 - Nombre: " + p2.Nombre);
			Console.WriteLine("p2 - Apellido: " + p2.Apellido);
			Console.WriteLine();

			/* Verifico si son el mismo objeto p y p2, ya que estamos
			 * dentro de la misma sesión */
			if (p == p2)
				Console.WriteLine("p y p2 son el mismo objeto");

			p2.Apellido = "Paduán";

			s.Flush();

			s.Close();
		}
	}
}
</pre>
<p>En el proyecto agregué estas referencias:</p>
<ul>
<li>NHibernate.dll</li>
<li>System</li>
</ul>
<p>Ahora vamos a lo que nos interesa. En el archivo <em>app.config</em> (que al compilar se traducirá a <NombreAssembly>.exe.config en el directorio de salida), observemos estas lineas:</p>
<pre lang="xml">
        ...
        <add
            key="hibernate.connection.driver_class"
            value="PruebaNHibernate.MonoDataSqliteDriver, PruebaNHibernate"
        />
        ...
</pre>
<p>NHibernate trae un driver para SQLite, como dije al principio, pero que utiliza un provider que fue discontinuado. Por lo tanto, para utilizar Mono.Data.Sqlite, cree una clase en mi assembly (PruebaNHibernate) con el nombre que se indica allí (MonoDataSqliteDriver):</p>
<pre lang="csharp">
using System;
using NHibernate.Driver;

namespace PruebaNHibernate
{
	public class MonoDataSqliteDriver : ReflectionBasedDriver
	{
		public MonoDataSqliteDriver()
			: base("Mono.Data.Sqlite",
			       "Mono.Data.Sqlite.SqliteConnection",
			       "Mono.Data.Sqlite.SqliteCommand")
		{
		}

		public override bool UseNamedPrefixInSql
		{
			get { return true; }
		}

		public override bool UseNamedPrefixInParameter
		{
			get { return true; }
		}

		public override string NamedPrefix
		{
			get { return "@"; }
		}

		public override bool SupportsMultipleOpenReaders
		{
			get { return false; }
		}
	}
}
</pre>
<p>En el constructor de la misma le paso a mi clase padre los argumentos que necesita: nombre del assembly (en este caso "Mono.Data.Sqlite"), clase para crear la conexión y ejecutar comandos. Desconozco los detalles de SQLite, así que copié los métodos sobreescritos del driver viejo.</p>
<p>No pude hacer que NHibernate cargue el assembly "Mono.Data.Sqlite" desde el GAC, así que hay que copiarlo al directorio del ejecutable. Es necesario copiar otros archivos, como las dependencias de NHibernate y la base de datos (data.db). Se pueden bajar el proyecto completo para MonoDevelop <a href='http://www.miltonpividori.com.ar/wp-content/uploads/2007/12/pruebanhibernatetarbz2.png' title='pruebanhibernatetarbz2.png'>aquí</a>. El archivo obviamente no es un png, pero sino no lo puedo subir <img src='http://www.miltonpividori.com.ar/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Ahora bien, <strong>hay un problemita</strong>... el archivo System.Data.dll que viene con Mono 1.2.4 en Gutsy tiene un bug que hará que el ejemplo no funcione. El mismo ya fue solucionado en la versión 1.2.6. Así que, como workaround, pueden bajarse el paquete de Debian <a href="http://packages.debian.org/sid/libmono-system-data2.0-cil">libmono-system-data2.0-cil</a> correspondiente a la versión 1.2.6 de Mono y sobreeescribir ese archivo, que se ubica en <em>/usr/lib/mono/gac/System.Data/2.0.0.0__b77a5c561934e089/</em>. Reporté el problema en Ubuntu, así que quizá lo actualicen dentro de poco.</p>
<p>Con esto podremos utilizar SQLite con NHibernate, bajo Mono, con un binding actualizado.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.miltonpividori.com.ar/2007/12/30/mono-nhibernate-sqlite/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>Gtk# &#8211; Aplicaciones sensibles</title>
		<link>http://www.miltonpividori.com.ar/2007/12/06/gtk-aplicaciones-sensibles/</link>
		<comments>http://www.miltonpividori.com.ar/2007/12/06/gtk-aplicaciones-sensibles/#comments</comments>
		<pubDate>Thu, 06 Dec 2007 15:53:20 +0000</pubDate>
		<dc:creator>miltondp</dc:creator>
				<category><![CDATA[Mono/.NET]]></category>
		<category><![CDATA[Software Libre]]></category>

		<guid isPermaLink="false">http://www.miltonpividori.com.ar/?p=180</guid>
		<description><![CDATA[En el TP de implementación de Adm. de Recursos desarrollamos con Nacho y César un cliente de mensajería instantánea muy simple. Está hecho en C# y para la GUI usamos Gtk#, todo corriendo en Mono. Por cierto, ésta es la página del proyecto por si quieren investigar el código y hacer algunas pruebas. Pero el [...]]]></description>
			<content:encoded><![CDATA[<p>En el TP de implementación de Adm. de Recursos desarrollamos con <a href="http://nacho.larrateguy.com.ar/">Nacho</a> y <a href="http://www.cesarsandrigo.com.ar/">César</a> un cliente de mensajería instantánea muy simple. Está hecho en C# y para la GUI usamos Gtk#, todo corriendo en <a href="http://www.mono-project.com/">Mono</a>. Por cierto, <a href="http://code.google.com/p/admrec/">ésta es la página del proyecto</a> por si quieren investigar el código y hacer algunas pruebas.</p>
<p>Pero el motivo del post no es este trabajo en sí, sino la solución a un problema que se había presentado. Utilizamos Remoting para comunicar los clientes con el servidor. Remoting es una tecnología para comunicar procesos, en la que podemos instanciar, por ejemplo, objetos remotos y llamar métodos del mismo, ejecutándose éstos en el servidor. Lo veo como algo muy parecido a RPC. Tampoco es el objetivo del post hablar de  Remoting, sino simplemente decir que cuando ejecutamos un método remoto, se abre un thread nuevo para llevar a cabo la ejecución del mismo en el servidor.</p>
<p><span id="more-180"></span><br />
En nuestro diseño (que quizá no sea el mejor, pero no importa), el servidor mantenía actualizada la lista de contactos de todos los clientes. Así, cuando se conectaba alguien, el servidor ejecutaba un método remoto de un objeto propio de los clientes, que se encargaba de actualizar el TreeView con el nuevo contacto recién conectado. Lo mismo pasaba cuando se recibía un mensaje nuevo enviado por un cliente a otro.</p>
<h2>Gtk.Application.Invoke()</h2>
<p>Notábamos que cuando se disparaban estos métodos remotos en el cliente, el cual actualizaba la interfaz gráfica, a veces se colgaba. No entendíamos por qué hasta que leímos un poco más sobre el funcionamiento interno de Gtk+. Algunos insultos recibió el toolkit antes de eso <img src='http://www.miltonpividori.com.ar/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  El artículo interesante y que nos ayudó es <a href="http://www.mono-project.com/Responsive_Applications">éste</a>. Resulta que Gtk+ es <strong>thread-aware</strong>, pero <strong>no thread-safe</strong>. O sea que, por lo que entiendo, en nuestra aplicación solamente el thread que ejecutó Application.Run puede acceder a los elementos de Gtk. Entonces nuestro problema era que ese thread (el que manejaba la ejecución del método remoto, distinto al thread principal) intentaba actualizar un TreeView directamente.</p>
<p>Entonces, lo que debemos hacer en el código de nuestro thread es encolar un evento para que sea ejecutado por el thread principal:</p>
<pre lang="csharp">
Gtk.Application.Invoke (delegate {
      label.Text = "Listo";
});</pre>
<p>Con ese <em>delegate</em> estoy declarando un método anónimo. La alternativa es crear un método aparte y pasarle a Invoke el nombre del método.</p>
<h2>Idle Handlers</h2>
<p>Todavía no me surgió la necesidad de usar esto, pero esta muy interesante, para tener en cuenta. Si necesitamos realizar cierta actividad cuando nuestro programa no está haciendo nada, podemos usar el siguiente código:</p>
<pre lang="csharp">
void Start ()
{
	GLib.Idle.Add (new IdleHandler (OnIdleCreateThumbnail));
}

bool OnIdleCreateThumbnail ()
{
	Image img = GetNextImage ();

	// If no more images remain, stop the idle handler.
	if (img == null)
		return false; 

	CreateThumbnail (img, img.ToString () + ".thumbnail");

	// There are more images, invoke this routine again on the next Idle moment.
	return true;
}
</pre>
<p>Esto está bueno, porque nos olvidamos de la complejidad de usar threads para éste proposito en particular. El funcionamiento parece ser bastante entendible al mirar el código de ejemplo de arriba.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.miltonpividori.com.ar/2007/12/06/gtk-aplicaciones-sensibles/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MonoReporter &#8211; Reportes en Mono</title>
		<link>http://www.miltonpividori.com.ar/2007/10/10/monoreporter-reportes-en-mono/</link>
		<comments>http://www.miltonpividori.com.ar/2007/10/10/monoreporter-reportes-en-mono/#comments</comments>
		<pubDate>Wed, 10 Oct 2007 13:19:13 +0000</pubDate>
		<dc:creator>miltondp</dc:creator>
				<category><![CDATA[Mono/.NET]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[ZaspeSharp]]></category>

		<guid isPermaLink="false">http://www.miltonpividori.com.ar/?p=154</guid>
		<description><![CDATA[Ya escribí un post sobre este tema. Desde ahí hasta hace un mes aproximadamente, MonoReporter quedó olvidado, ya que en realidad no lo necesitaba con tanta urgencia&#8230; pero ahora sí. Es lo que sigue por hacer en Zaspe#: la generación de reportes. Mi idea era hacer algo que no sólo me sirva a mí, sino [...]]]></description>
			<content:encoded><![CDATA[<p>Ya escribí un <a href="http://www.miltonpividori.com.ar/?p=40">post</a> sobre este tema. Desde ahí hasta hace un mes aproximadamente, MonoReporter quedó olvidado, ya que en realidad no lo necesitaba con tanta urgencia&#8230; pero ahora sí. Es lo que sigue por hacer en <a href="http://code.google.com/p/zaspe-sharp/">Zaspe#</a>: la generación de reportes.</p>
<p>Mi idea era hacer algo que no sólo me sirva a mí, sino que lo pueda usar otra persona también. Cuando le comenté la idea a <a href="http://nacho.larrateguy.com.ar/">Nacho</a>, sobre un lenguaje basado en XML para describir el reporte, me propuso leer un SVG, hecho con Inkscape por ejemplo&#8230; así me ahorraría un futuro diseñador de reportes. Eso es lo que he hecho.</p>
<p>MonoReporter entonces lee de un SVG hecho con Inkscape (lo aclaro porque sobre este software hice las pruebas), y lo transforma a instrucciones para dibujar con <a href="http://en.wikipedia.org/wiki/Cairo_%28graphics%29">Cairo</a> y <a href="http://www.gnome.org/~alexl/presentations/guadec2006-printing.pdf">GtkPrint</a> (el nuevo sistema de impresión de Gtk+). Es posible, por ejemplo, exportar directamente a PDF, o mostrar el diálogo de impresión, tanto en GNU/Linux como Windows (previa instalación de los runtimes de gtk-sharp que se pueden encontrar en la <a href="http://code.google.com/p/zaspe-sharp/">web de zaspe#</a>). A esto lo realiza en forma nativa.</p>
<p><span id="more-154"></span><br />
Para leer el XML (SVG), simplemente uso las clases en el namespace <em>System.Xml</em>. No utilizo ninguna librería externa. He probado una, <a href="http://www.jbrowse.com/svgnet/">SvgNet</a>, un proyecto poco activo (último release en el 2003). Y me he dado cuenta de que tenía que adaptarlo mucho&#8230; así que opté por crear mis propias clases de lectura del SVG, que terminó siendo un trabajo bastante sencillo en realidad.</p>
<p>Debido a algunas limitaciones que tengo en Windows (como los bindings de Cairo sólo disponibles para el profile 1.0), el diseño en general de las clases no es el mejor, o por lo menos el que me hubiese gustado.</p>
<p>Este es un ejemplo de uso de MonoReporter con C# (en realidad, se puede utilizar con cualquier lenguaje de .NET):</p>
<pre lang="csharp">
using System.Data;
using MonoReporter;

...

Report report = new Report("PruebaMonoReporter", "test.svg");
report.Data["titulo"] = "Listado de personas";

DataTable personsTable = new DataTable();

DataColumn[] columns = new DataColumn[4];
columns[0] = new DataColumn("nombre");
columns[1] = new DataColumn("apellido");
columns[2] = new DataColumn("dni");
columns[3] = new DataColumn("direccion");
personsTable.Columns.AddRange(columns);

DataRow d1 = personsTable.NewRow();
d1["nombre"] = "Milton";
d1["apellido"] = "Pividori";
d1["dni"] = "99999999";
d1["direccion"] = "dirección";
personsTable.Rows.Add(d1);

d1 = personsTable.NewRow();
d1["nombre"] = "Pepe";
d1["apellido"] = "Biondi";
d1["dni"] = "11111111";
d1["direccion"] = "alguna dirección";
personsTable.Rows.Add(d1);

d1 = personsTable.NewRow();
d1["nombre"] = "Juan";
d1["apellido"] = "Sanchez";
d1["dni"] = "33333333";
d1["direccion"] = "otra dirección";
personsTable.Rows.Add(d1);

report.DataTables["personas"] = personsTable;

report.Run(myWindow);
</pre>
<p><em>DataTable</em> es una clase del namespace System.Data.</p>
<p><em>Report</em> es una clase de MonoReporter, la principal. En las primeras lineas se crea un nuevo reporte con un título dado, y un archivo SVG de donde leer el diseño del reporte. La propiedad <em>Data</em> devuelve un Hashtable, en el que podemos setear el texto que queramos al elemento SVG indicado por la clave. En este caso, se está diciendo que al momento de generar el reporte, al elemento con id (lo cambiamos desde Inkscape) &#8220;titulo&#8221; le asigne el valor &#8220;Listado de personas&#8221;.</p>
<p>Una vez creado el DataTable, le indicamos la fuente de datos para la &#8220;tabla&#8221; llamada &#8220;personas&#8221;. Una &#8220;tabla&#8221; es un concepto inventado, que se forma creando varios elementos de texto en Inkscape, tantos como columnas haya, y dándole a cada uno el nombre de la columna (que definimos en el DataTable). Luego se los agrupa, y a esa agrupación se le coloca un nombre. El nombre en este caso es &#8220;personas&#8221;.</p>
<p>De esta forma cuando MonoReporter encuentra un layer con sólo nodos &#8220;text&#8221;, sabe que se trata de una tabla. <a href='http://www.miltonpividori.com.ar/wp-content/uploads/2007/10/pdffinal.pdf' title='pdffinal.pdf'>Este es el archivo PDF final</a> que genera el código de arriba.</p>
<p>Quedan muchas (muchísimas) cosas por hacer, a tal punto de que ni siquiera es usable: por el momento se pueden generar reportes de una sola página <img src='http://www.miltonpividori.com.ar/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  Algunas cosas que faltan por hacer:</p>
<ul>
<li>Soporte para reportes largos (de más de una página).</li>
<li>Soporte para más elementos gráficos de SVG (por ahora reconoce rectángulos, líneas y texto).</li>
<li>Mayor nivel de personalización: por ejemplo, el espacio entre filas no se puede cambiar.</li>
<li>Soporte para la inclusión de imágenes.</li>
<li>Etc etc etc&#8230;</li>
</ul>
<p>Algunas limitaciones:</p>
<ul>
<li>A los textos sólo se los puede redimensionar aumentando su tamaño de fuente, o sea, sin utilizar las flechas.</li>
<li>Raramente, algunos colores son bien leidos, pero otros no, como el verde.</li>
<li>Y muchas más&#8230;</li>
</ul>
<p>El código fuente se encuentra <a href="http://zaspe-sharp.googlecode.com/svn/trunk/zaspe-sharp/MonoReporter/">aquí</a>, en el mismo repositorio que Zaspe#. Está bajo la GPLv3.</p>
<p>Si alguien tiene algún comentario, alguna mejora o sugerencia para encarar esto mejor&#8230; bienvenido sea!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.miltonpividori.com.ar/2007/10/10/monoreporter-reportes-en-mono/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>ZaspeSharp 0.0.2</title>
		<link>http://www.miltonpividori.com.ar/2007/07/24/zaspesharp-002/</link>
		<comments>http://www.miltonpividori.com.ar/2007/07/24/zaspesharp-002/#comments</comments>
		<pubDate>Tue, 24 Jul 2007 13:47:37 +0000</pubDate>
		<dc:creator>miltondp</dc:creator>
				<category><![CDATA[Mono/.NET]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[ZaspeSharp]]></category>

		<guid isPermaLink="false">http://www.miltonpividori.com.ar/?p=149</guid>
		<description><![CDATA[La primera versión fue en realidad una especie de prototipo. Esta versión, que la liberé hace unos días y bajo la flamante GPLv3, se acerca más a algo usable: se pueden agregar, modificar y eliminar personas y eventos, y también ingresar las asistencias. Sin embargo todavía le falta la generación de estadísticas y reportes, que [...]]]></description>
			<content:encoded><![CDATA[<p>La primera versión fue en realidad una especie de prototipo. Esta versión, que la liberé hace unos días y bajo la flamante GPLv3, se acerca más a algo usable: se pueden agregar, modificar y eliminar personas y eventos, y también ingresar las asistencias. Sin embargo todavía le falta la generación de estadísticas y reportes, que es una parte muy importante.</p>
<p>Funciona en GNU/Linux con Mono (yo lo estoy probando con la versión 1.2.3 que viene en Ubuntu Feisty)  o en Windows con .NET Framework 2.0 y el runtime de gtk-sharp 2.10 (que se lo pueden bajar de la página del proyecto).</p>
<p>Si les interesa probarlo, se pueden bajar los archivos desde <a href="http://code.google.com/p/zaspe-sharp/downloads/list">la página de descargas del proyecto</a>.</p>
<p>Una aclaración para el uso: cuando lo ejecutan, verán al inicio la lista de asistencias vacía. Para que se habilite tienen que ingresar por lo menos una persona, y por lo menos un evento anterior a la fecha actual (ya que no tiene sentido ingresar las asistencias para un evento futuro). Si a alguien le es útil algo así, y tiene ideas para mejorarlo, por favor, están invitados a dejar un comentario en este post, o un <a href="http://code.google.com/p/zaspe-sharp/issues/list">issue</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.miltonpividori.com.ar/2007/07/24/zaspesharp-002/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Mono/.NET: No importa el lenguaje</title>
		<link>http://www.miltonpividori.com.ar/2007/07/21/mononet-no-importa-el-lenguaje/</link>
		<comments>http://www.miltonpividori.com.ar/2007/07/21/mononet-no-importa-el-lenguaje/#comments</comments>
		<pubDate>Sat, 21 Jul 2007 16:37:48 +0000</pubDate>
		<dc:creator>miltondp</dc:creator>
				<category><![CDATA[Facultad]]></category>
		<category><![CDATA[Mono/.NET]]></category>
		<category><![CDATA[Software]]></category>

		<guid isPermaLink="false">http://www.miltonpividori.com.ar/?p=148</guid>
		<description><![CDATA[Una de las cosas que vamos a probar en el trabajo práctico de implementación de Administración de Recursos, es qué tan cierto es eso de que Mono/.NET es independiente del lenguaje. Bueno, estuve haciendo unas pruebas con Python y C#. Hay una implementación de código abierto (bajo la licencia de Microsoft Ms-PL) del intérprete de [...]]]></description>
			<content:encoded><![CDATA[<p>Una de las cosas que vamos a probar en el trabajo práctico de implementación de Administración de Recursos, es qué tan cierto es eso de que Mono/.NET es independiente del lenguaje.</p>
<p>Bueno, estuve haciendo unas pruebas con Python y C#. Hay una implementación de código abierto (bajo la licencia de Microsoft <a href="http://www.codeplex.com/IronPython/Project/License.aspx">Ms-PL</a>) del intérprete de Python escrita en C#, que permite ejecutar estos programas compilando el código Python a CIL (el código intermedio). También tiene una consola, como Python, y es posible utilizar toda la biblioteca de .NET. Se llama <a href="http://www.codeplex.com/IronPython">IronPython</a>.</p>
<p>Esta implementación, en su versión estable actual 1.1, tiene compatibilidad con CPython 2.4.4. Esto significa que un programa escrito para ser corrido con Python 2.4.4 puede correrse también con IronPython 1.1. Sin embargo no es que podemos correr cualquier cosa hecha para Python con IronPython: un juego que utiliza el módulo PyGame no funciona (por lo menos yo no pude).</p>
<p>Les voy a mostrar un ejemplo en el que desde Python creo una clase que hereda de otra creada en C#. Sip, ¡esto está muy bueno!</p>
<p><span id="more-148"></span></p>
<p>Esta es la clase <em>Persona</em> (si, es algo bien sencillo) en C#:</p>
<pre lang="csharp">
using System;

public class Persona
{
	private string nombre;
	private string apellido;

	public Persona(string nombre, string apellido)
	{
		this.nombre = nombre;
		this.apellido = apellido;

		Console.WriteLine("Constructor C#");
	}

	public string Nombre
	{
		get { return this.nombre; }
		set { this.nombre = value; }
	}

	public string Apellido
	{
		get { return this.apellido; }
		set { this.apellido = value; }
	}

	public string NombreEnMayusculas
	{
		get {
			return this.nombre.ToUpper();
		}
	}

	public string ApellidoEnMayusculas
	{
		get {
			return this.apellido.ToUpper();
		}
	}
}
</pre>
<p>Para los que no conocen C#, esas cuatro ultimas cosas raras que están definidas se llaman <em>propiedades</em>. Vienen a reemplazar los getters y setters. Así, en lugar de setear el nombre con un <em>objeto.setNombre(&#8220;Nombre nuevo&#8221;)</em>, lo hacemos con un <em>objeto.Nombre = &#8220;Nombre nuevo&#8221;</em>. Pueden ser de sólo lectura (cuando hay sólo un <em>get</em>), sólo escritura, o lectura/escritura.</p>
<p>En fin, la clase Python es esta:</p>
<pre lang="python">
import clr
clr.AddReferenceToFile("Persona.dll")

import Persona

class Mujer(Persona):

    def imprimirNombreCompleto(self):
        print self.Nombre + ' ' + self.Apellido

    def nombreEnMinusculas(self):
        return self.Nombre.lower()

    def apellidoEnMinusculas(self):
        return self.Apellido.lower()

x = Mujer('Juana', 'Vargas')
x.imprimirNombreCompleto()

print x.NombreEnMayusculas + ' ' + x.ApellidoEnMayusculas
print x.nombreEnMinusculas() + ' ' + x.apellidoEnMinusculas()
print x.nombreEnMinusculas() + ' ' + x.ApellidoEnMayusculas
</pre>
<p>(Cuando copian y pegan, las comillas simples se cambian. Así que no va a compilar a menos que las reemplacen)</p>
<p>Los pasos para probar este codigo son:</p>
<ol>
<li>Compilar la clase hecha en C# a una librería (Persona.dll) ejecutando: &#8220;mcs -t:library -out:Persona.dll Persona.cs&#8221;, suponiendo que han llamado al archivo de la clase C# <em>Persona.cs</em></li>
<li>Instalan la versión Community Edition de IronPython (IPCE). La pueden bajar <a href="http://sourceforge.net/project/showfiles.php?group_id=178069&#038;package_id=209325&#038;release_id=509859">aquí</a>. Hay que agregar a la variable de entorno PATH el lugar donde lo descompriman.</li>
<li>Corren el archivo Mujer.py (suponiendo que así lo han llamado) con IronPython: &#8220;ipy.exe Mujer.py&#8221;</li>
</ol>
<p>La salida de eso es:</p>
<pre>
Constructor C#
Juana Vargas
JUANA VARGAS
juana vargas
juana VARGAS
</pre>
<h2>Python desde C#</h2>
<p>Lamentablemente el ejemplo anterior invertido no es posible (crear una clase en C# que herede de la de Python), sin embargo obvio que sí se pueden ejecutar métodos y otras cosas.</p>
<p>Python es un lenguaje dinámico, y esta característica complica las cosas. Si bien IronPython ha demostrado que <a href="http://en.wikipedia.org/wiki/Common_Language_Runtime">CLR</a> (Common Language Runtime) tiene buen soporte para los lenguejes dinámicos, se está trabajando en una capa que está encima de CLR, llamada <a href="http://en.wikipedia.org/wiki/Dynamic_Language_Runtime">DLR</a> (Dynamic Language Runtime) que lo hace muchísimo mejor para este tipo de lenguajes. DLR hace que sea mucho más fácil implementar lenguajes dinámicos en .NET, además de poder compartir código con otros lenguajes (dinámicos y estáticos).</p>
]]></content:encoded>
			<wfw:commentRss>http://www.miltonpividori.com.ar/2007/07/21/mononet-no-importa-el-lenguaje/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

