C#3.0, LINQ / Expresiones Lambda

Viernes, 22 de Mayo de 2009 Nessy Sin comentarios

c#3.0 - linq - lambda

LINQ - Language Integrated Query / Expresiones Lambda

Introducido en la versión 3.0 de .NET, LINQ nos permite realizar consultas similar a las de SQL en nuestro código.

Lambda es una forma de escribir funciones anónimas en el cual se lo suele usar para pasar con facilidad como argumentos y para crear delegados.

Todo esto combinado con el uso de los genéricos hace que el código sea simple.

Veamos un ejemplo de código con LINQ:

	Ficha ficha = (from child in Children.OfType<Ficha>()
				   where child.Name == "_1"
				   select child).First<Ficha>() as Ficha;

La sintaxis es idéntica al SQL, en este caso necesitábamos extraer un elemento de tipo "Ficha" con el nombre "_1" de la propiedad "Children" que devuelve una colección de objetos (En Silverlight, "Children" es una propiedad que representa un contenedor de donde desprende los elementos gráficos que se muestra en pantalla).

Ahora ajustando el mismo código con una expresión Lambda:

	Ficha ficha = Children
				  .OfType<Ficha>()
				  .Where(child => child.Name == "_1")
				  .First<Ficha>();

o simplificandolo mas:

	Ficha ficha = Children
				  .OfType<Ficha>()
				  .Single(child => child.Name == "_1");

Todo muy lindo pero el ejemplo que propuse no creo que sorprenda a los programadores Flash dado que a nivel funcional lo que quiero hacer es equivalente a "getChildByName". Osea en código AS3 seria:

var ficha:Ficha = this.getChildByName("_1") as Ficha;

Leer XML con Silverlight 2

Lo que sigue ahora, sí es impresionante, el ejemplo que propongo a continuación es con Silverlight 2 y se trata de leer un XML con LINQ.

Tengo el XML siguiente, sites.xml:

<?xml version="1.0" encoding="UTF-8"?>
<main>
	<sites>
		<site
			name="Blog"
			link="http://www.nessy.com.ar/blog"
			thumb="thumb.blog.jpg" />
		<site
			name="LinkedIn"
			link="http://www.linkedin.com/in/FranciscoRosales"
			thumb="thumb.linkedin.jpg" />
		<site
			name="Twitter"
			link="http://www.twitter.com/nessy"
			thumb="thumb.twitter.jpg" />
	</sites>
</main>

En consecuencia tengo el objeto siguiente:

using System;

namespace NessyJackSL.model
{
	public class Site
	{
		public string name { get; set; }

		public string link { get; set; }

		public string thumb { get; set; }
	}
}

Y finalmente tengo la clase llamada JackData que se encargará de leer el XML:

using System;
using System.Net;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using NessyJackSL.util;
using NessyJackSL.model;

namespace NessyJackSL.data
{
	public class JackData
	{
		public event EventHandler EVENT_DATA_READY;

		public static Site[] sites;

		public JackData()
		{
			try
			{
				WebClient client = new WebClient();
				client.OpenReadAsync(new Uri("sites.xml", UriKind.Relative));
				client.OpenReadCompleted += new OpenReadCompletedEventHandler(onComplete);
			}
			catch (Exception ex)
			{
				Log.w("JackData.Error > " + ex.Message);
			}
		}

		private void onComplete(object sender, OpenReadCompletedEventArgs evt)
		{
			XDocument doc = XDocument.Load((Stream) evt.Result);
			sites = (from site in doc.Descendants("site")
					 select new Site
					 {
						name = site.Attribute("name").Value,
						link = site.Attribute("link").Value,
						thumb = site.Attribute("thumb").Value
					 }).ToArray();
			EVENT_DATA_READY(this, new EventArgs());
		}
	}
}

Presten atención a lo que se hace en el código siguiente extraido de la clase JackData:

			XDocument doc = XDocument.Load((Stream) evt.Result);
			sites = (from site in doc.Descendants("site")
					 select new Site
					 {
						name = site.Attribute("name").Value,
						link = site.Attribute("link").Value,
						thumb = site.Attribute("thumb").Value
					 }).ToArray();

Una vez cargado el XML sites.xml, estas pocas líneas de código efectúan las acciones siguientes:
recorre los nodos con nombre "site", crea un objeto asignándole el valor que proviene del atributo que le corresponde por cada nodo encontrado y se lo agrega al Array, al final devuelve un Array de Site.

Ahora también lo podemos hacer con la combinación de la expresión Lambada:

			sites = doc
					.Descendants("site")
					.Select(
						site => new Site
						{
							name = site.Attribute("name").Value,
							link = site.Attribute("link").Value,
							thumb = site.Attribute("thumb").Value
						}
					).ToArray();

Mi polémica afirmación es que no he visto esta simplicidad en ningún otro lenguaje de programación conocidos pero existen desarrollos en curso para adaptarlos a los lenguajes mas populares.

Las opciones para Java son Quare (http://quaere.codehaus.org/) y JLinq (http://www.hugoware.net/).

Para ActionScript 3 es GAIQL (http://g-unix.com/blog/1/2008/05/Actionscript-Intergrated-Query-Language-Preview-Release.cfm).

Para PHP se llama PHPLinq (http://phplinq.codeplex.com/).

Javascript parece tener su Lambda: http://alex.dojotoolkit.org/2009/05/on-js-lambdas/.

Categories: C#, Silverlight Tags: ,

300 – Un sistema de sorteo en AS3

Jueves, 19 de Marzo de 2009 Nessy Sin comentarios

Comparto la experiencia que me toco al realizar una pequeña aplicación que sortea números ganadores.

La consigna: mostrar números aleatorios (300) que no se repitan en ninguna caso y que los muestres con un efecto de suspenso parecido a los números de los paneles de los aeropuertos.

La dificultad: El panel tenia que tener 7 dígitos en el cual giraban los números consecutivamente del 1 al 10 al mismo tiempo, esto provocaba un gran consumo de procesador lo cual lo hacia inutilizable en una computadora con bajo recursos.

Mas dificultad: La computadora donde tenia que correr era una Notebook con un procesador de 1.7 Ghz y memoria de 512 Mb.

Intentos: Mi primera prueba para efectuar el "Flip" de los números fue de utilizar el eje Z introducido en el nuevo Player del flash. Este método resulto tedioso para posicionar correctamente los números en la pantalla a lo cual decidí usar Papervision3D. Esa tecnología me resulto efectiva para mostrar en pantalla los números pero fue fatal para el procesador de computadoras de bajo recursos.

La solución: engañar el ojo humano simulando el 3D con un efecto “Blur” en cada numero cuando van bajando (es un viejo truco pero sigue siendo efectivo). Esto me permitio girar los numero a alta velocidad y a agregarle sonido para cada numero.

Foto del sistema de sorteo

Categories: Actionscript Tags:

Consumir Webservice con SAP / ABAP

Miércoles, 18 de Marzo de 2009 Nessy 6 comentarios

Un ejemplo simple de como consumir Webservice (hecho en .NET) con SAP / ABAP, ya que los ejemplos encontrados en la web en general no me resultaron muy didáctico.

El Webservice a titulo de ejemplo tiene los sigientes parametros: title y details.

REPORT zwebconsume.

DATA: http_client TYPE REF TO if_http_client .

DATA: w_string TYPE string ,
w_result
TYPE string ,
r_str
TYPE string .

DATA: result_tab TYPE TABLE OF string.

START-OF-SELECTION .
CLEAR w_string .
w_string = 'http://urlhost/Logs/main.asmx/SetLog'.

CALL METHOD cl_http_client=>create_by_url
EXPORTING
url                = w_string
IMPORTING
client = http_client
EXCEPTIONS
argument_not_found =
1
plugin_not_active  =
2
internal_error     =
3
OTHERS = 4.

CALL METHOD HTTP_CLIENT->REQUEST->SET_HEADER_FIELD
EXPORTING
NAME =
'~request_method'
VALUE = 'POST'.

CALL METHOD http_client->REQUEST->SET_FORM_FIELD
EXPORTING
NAME =
'title'
VALUE = 'Mail sistema'.

CALL METHOD http_client->REQUEST->SET_FORM_FIELD
EXPORTING
NAME =
'details'
VALUE = 'Funcion 1234'.

CALL METHOD http_client->send
EXCEPTIONS
http_communication_failure =
1
http_invalid_state         =
2.

CALL METHOD http_client->receive
EXCEPTIONS
http_communication_failure =
1
http_invalid_state         =
2
http_processing_failed     =
3.
CLEAR w_result .
w_result = http_client->response->get_cdata( ).

REFRESH result_tab .
SPLIT w_result AT cl_abap_char_utilities=>cr_lf INTO TABLE
result_tab .

READ TABLE result_tab INTO r_str INDEX 2.

Lo que hay que tener en cuenta es que el envio de parametros se efectua con REQUEST->SET_FORM_FIELD y no con REQUEST->SET_DATA ya que este es para enviar todo el encabezado.

Tambien la invocación siguiente es para pasar los parametros por el metodo POST:

CALL METHOD HTTP_CLIENT->REQUEST->SET_HEADER_FIELD
EXPORTING
NAME =
'~request_method'
VALUE = 'POST'.