Etiquetado: C#

Closures en C#

Para empezar el año y mientras esperamos la llegada de Marty McFly, un minipost sobre closures, una estructura imprescindible en JavaScript y otros lenguajes funcionales, pero ¿las podemos hacer en C#? Y la respuesta es:
¡Por supuesto! Y aquí tenéis un ejemplo:

public static Func<int> Fib()
{
    int a = 0, b = 1;
    return () => { var temp = b; b = a + b; return a=temp; };
}

static void Main(string[] args)
{
    var fib=Fib();

    for (int i = 0; i < 12;i++ )
        Console.Write("{0} ", fib());
}

Como veis el uso de funciones anónimas nos ayuda mucho. El ejemplo lo he sacado de otro lenguaje sobre el que estaba leyendo. Yo ahora me voy a buscar un monopatín 😉

Anuncios

La palabra clave yield

La semana pasada el maestro Eduard Tomás propuso la solución del reto MSDN utilizando la palabra clave yield en un método para evitar el uso de una colección adicional.

¿Qué se esconde tras esta palabra clave?

El patrón Iterator

Si has escrito código C# alguna vez, ya conocerás las interfaces IEnumerable e IEnumerable<T> que permiten recorrer fácilmente una colección con la palabra clave foreach:

IEnumerable<int> list=new int[]{1,2,3,4};
//...
foreach (var value in list)
{
    //do something
}

Como veis en el ejemplo, este interfaz lo implementan todas las colecciones desde los tipos más básicos como el Array (aunque de una forma un tanto particular).

El interfaz sólo tiene un método, GetEnumerator que devuelve un IEnumerator, que nos devolverá una clase que es la que realmente sabe iterar sobre nuestra colección de elementos. Es el típico patrón Iterator del GoF (Design Patterns: Elements of Reusable Object-Oriented Software).

Sigue leyendo

Caché HTTP de cliente en C# (1 de 4): aplicaciones de escritorio

Hoy en día es muy habitual utilizar contenido web en nuestras aplicaciones y eso penaliza el rendimiento. Para mejorarlo vamos a tener que almacenar en caché dicho contenido. Hacerlo bien no es difícil, pero es necesario conocer cómo funcionan los mecanismos de caché en la web y buscar dentro de la documentación de .Net cómo podemos aprovechar estos.

Upload / Download
Upload / Download por johntrainor, en Flickr

Como no soy el primero en tener la necesidad, existen algunas entradas en StackOverflow sobre el tema. Parece que la solución propuesta funciona bien, pero todas los que he visto se olvidan de algunos puntos importantes, como por ejemplo pedir al servidor si hay una versión actualizada del archivo, añadir técnicas de scavenging para que el contenido descargado caduque, etc. Además se olvidan de que el sistema operativo ya sabe cachear y es un poco raro que tengamos que volver a programar el caché que tan bien hacen los navegadores.

Te recomiendo leer el artículo hasta el final, pero si tienes mucha prisa puedes descargar el código de ejemplo en GitHub.

Sigue leyendo

Patos y código C#

Swimmer duck on Surfboard
Durante los primeros días del año trajo mucha cola un artículo de Eric Lippert, uno de los padres de C#, sobre su visión de qué es el Duck Typing y qué representa para él en lenguajes de tipificado principalmente estático (digo principalmente porque ya sabemos que en .Net podemos hacer muchas cosas raras :P).

En mi opinión, más que criticar el concepto de duck typing, ese artículo es una queja sobre el bajo nivel y falta de coherencia de los artículos de Wikipedia y para demostrar que las modas confunden a la comunidad de desarrolladores. Deja claro que la entrada está mal escrita, usa mal algunos términos y se va contradiciendo según el párrafo.

En cualquier caso, para gustos los colores y yo os voy a contar mi visión al respecto del duck typing. No pretendo rebatir a Eric Lippert, no tengo ni los conocimientos ni la experiencia de Eric y otra gente como él que han hablado sobre el tema, sino que quiero dar mi opinión como desarrollador raso tras unos cuantos años utilizando el concepto en lenguajes como JavaScript y Python. Estoy de acuerdo en que el término es confuso, porque en realidad no tiene que ver directamente con el tipo que tengan los argumentos que enviamos, sino en cómo maneja el desarrollador los valores de los parámetros de sus métodos.

El nacimiento del pato tipificado (con lo bien que sonaba en inglés)

Para los que no conocéis el concepto, la frase que define el duck typing es, traducida, algo así:

Si anda como un pato y parpa como un pato entonces es un pato.

Detrás de esa frase tan simple veremos que hay que leer entre líneas y conocer un poco la historia. La discusión original era sobre cómo manejar el polimorfismo en Python y derivó en si se debía o no comprobar el tipo del objeto que llegaba en un parámetro de función. Los argumentos de Alex Martelli fueron que era mejor dejar de comprobar si el objeto que recibes es exactamente el tipo que te esperabas, sino que si el parámetro tiene las propiedades y métodos que necesitas, utilízalo sin más, si te falta algo lanza una excepción y que se preocupe el que envió al método un objeto inadecuado, todo esto acuñado bajo el símil del pato.

Yo añadiría que el Duck Typing es una convención a la hora de desarrollar porque el que utiliza el método o función debe saber que quien desarrolló ese método está utilizando duck typing, si no están los dos de acuerdo puede ser un auténtico desastre, sobre todo en lenguajes dinámicos (o en porciones dinámicas del código) donde nadie te avisa si estás haciendo algo “ilegal” hasta el momento de su ejecución.
Si pensáis que exagero, imaginad que pasaría si a una función JavaScript que se esperaba un pato le pasáis una bomba:

function vuelaAlto(pato){
    pato.volar(20);
}

var pato= {altura:0, volar: function(dif){this.altura+=dif; console.log(this.altura);}};
var bomba= {altura:0, volar: function(){console.log('¡booom!');},
            lanzar:function(dif){this.altura+=dif; console.log(this.altura);} };

vuelaAlto(pato);
vuelaAlto(bomba);

Aún así, tiene más ventajas que inconvenientes, tanto que, por ejemplo, en JavaScript lo utilizamos constantemente. Basta ver un ejemplo cualquiera de la librería jquery, donde enviamos un objeto anónimo con las propiedades que queremos enviar a la función, sin necesidad de crear una instancia de un tipo en concreto, basta que tenga la forma adecuada:

$.ajax({
  url: "test.html",
  context: document.body
}).done(function() {
  $( this ).addClass( "done" );
});

Duck typing en C#

Uno de los argumentos de Eric es que en realidad Duck Typing se refiere a Late Binding, y eso es algo que siempre hemos tenido en .Net y C#, e incluso en lenguajes más antiguos cuando surgió COM y podíamos ejecutar comandos de un Excel desde un programa hecho en Visual Basic. También dice que en cualquier otro caso tenemos los interfaces y que los lenguajes que lo implementan de forma estática en realidad a eso se le llama Structural Typing, como en Scala, Haskell o GO.

Otros autores opinan que duck-typing es bastante más que eso, por eso he dicho antes que el concepto me parece más una convención que otra cosa, veamos algunos casos que surgen en C# y si creo o no que tienen que ver con duck-typing:

Late Binding

En realidad, late-binding no es duck-typing ni creo que se le parezca. Cuando haces late-binding instancias de forma dinámica, normalmente por el nombre de la clase, un elemento que se corresponde con un tipo en concreto que está en un ensamblado al que no tenías acceso durante la compilación. Luego asignas ese objeto a una variable del tipo que tú sabes manejar y eso sólo puede pasar si el objeto es de ese tipo o hereda del mismo, al contrario que si usamos duck typing donde no tienen por qué ser del mismo tipo, sólo necesitas que se parezcan en las formas.

Normalmente en C# hacemos late-binding usando Reflection con métodos como Activator.CreateInstance(t) y asignando el resultado a un tipo en concreto, mediante un typecasting, de forma que luego nuestro código pueda utilizar ese objeto, por ejemplo:

Assembly assembly = Assembly.Load("ClassLibrary1");
Type type=assembly.GetType("ClassLibrary1.Form1");
Form form = (Form)Activator.CreateInstance(type);
form.Show();

A partir del typecasting con el tipo Form pasamos a utilizar el objeto como lo que es, un Form y si no lo fuera obtendríamos un error en tiempo de ejecución. Aquí está la gran diferencia con duck-typing, pues si utilizáramos este concepto nos bastaría que el objeto tuviera un método Show y no nos haría falta que el objeto heredara de Form, aunque eso sí, eso tiene una penalización de rendimiento.

dynamic

Con la palabra reservada dynamic, que trajo C# 4.0, si que podemos hacer duck-typing, pues nos proporciona la flexibilidad de los lenguajes dinámicos al no hacer typecasting contra ningún tipo concreto, sino que realiza una búsqueda del método o propiedad que nosotros estamos invocando, todo esto en tiempo de ejecución, como cualquier otro lenguaje dinámico. Si os estáis preguntando si es más lento, estáis en lo cierto. En el caso del late-binding sólo ralentiza mientras busca cómo hacer el binding, una vez enlazado el objeto ya se comporta de forma completamente normal, tanto en funcionamiento como en rendimiento.
En el caso de dynamic la penalización de rendimiento es alta y sólo se debería usar si es imposible saber con antelación el tipo.
Es fácil de comprobar si hacemos un ILDASM de una llamada dynamic contra una llamada con interfaz. Veremos cómo la cantidad de código se multiplica por 5, además de acceder al método utilizando un string en lugar de una posición de la tabla virtual.

public class Duck
{
    public string Quack()
    {
        return "Quack!";
    }
}
class Program
{
    static void Main(string[] args)
    {
        var duck = new Duck();
        var ventriloquistDuck = new { Quack = (Func<string>)(() => "Woof") };

        doQuackStatic(duck);

        doQuack(duck);
        doQuack(ventriloquistDuck);

        var notADuck = "Do you quack?";
        try
        {
            doQuack(notADuck);
        }
        catch
        {
            Console.WriteLine("Cannot quack!");
        }
        try
        {
            doQuack(25);
        }
        catch
        {
            Console.WriteLine("Cannot quack!");
        }
    }

    private static void doQuack(dynamic duck)
    {
        Console.WriteLine("Dynamic: {0} says {1}", duck.GetType(), duck.Quack());
    }

    private static void doQuackStatic(Duck duck)
    {
        Console.WriteLine("Static: {0} says {1}", duck.GetType(), duck.Quack());
    }
}

Aquí va el código IL de doQuackStatic tal como me lo da ILDASM tras compilar en modo Release:

.method private hidebysig static void  doQuackStatic(class DuckTyping.Duck duck) cil managed
{
  // Code size       23 (0x17)
  .maxstack  8
  IL_0000:  ldstr      "Static: {0} says {1}"
  IL_0005:  ldarg.0
  IL_0006:  callvirt   instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()
  IL_000b:  ldarg.0
  IL_000c:  callvirt   instance string DuckTyping.Duck::Quack()
  IL_0011:  call       void [mscorlib]System.Console::WriteLine(string,
                                                                object,
                                                                object)
  IL_0016:  ret
} // end of method Program::doQuackStatic

Y aquí el del método dinámico, lo he colapsado porque ocupa 130 líneas, pulsa sobre el nombre para ver el código:

.method private hidebysig static void  doQuack(object duck) cil managed
{
  .param [1]
  .custom instance void [System.Core]System.Runtime.CompilerServices.DynamicAttribute::.ctor() = ( 01 00 00 00 ) 
  // Code size       284 (0x11c)
  .maxstack  13
  .locals init ([0] class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo[] CS$0$0000,
           [1] class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo[] CS$0$0001,
           [2] class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo[] CS$0$0002)
  IL_0000:  ldsfld     class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`5<class [System.Core]System.Runtime.CompilerServices.CallSite,class [mscorlib]System.Type,string,object,object>> DuckTyping.Program/'<doQuack>o__SiteContainer2'::'<>p__Site3'
  IL_0005:  brtrue.s   IL_005c
  IL_0007:  ldc.i4     0x100
  IL_000c:  ldstr      "WriteLine"
  IL_0011:  ldnull
  IL_0012:  ldtoken    DuckTyping.Program
  IL_0017:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
  IL_001c:  ldc.i4.4
  IL_001d:  newarr     [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
  IL_0022:  stloc.0
  IL_0023:  ldloc.0
  IL_0024:  ldc.i4.0
  IL_0025:  ldc.i4.s   33
  IL_0027:  ldnull
  IL_0028:  call       class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags,
                                                                                                                                                                             string)
  IL_002d:  stelem.ref
  IL_002e:  ldloc.0
  IL_002f:  ldc.i4.1
  IL_0030:  ldc.i4.3
  IL_0031:  ldnull
  IL_0032:  call       class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags,
                                                                                                                                                                             string)
  IL_0037:  stelem.ref
  IL_0038:  ldloc.0
  IL_0039:  ldc.i4.2
  IL_003a:  ldc.i4.0
  IL_003b:  ldnull
  IL_003c:  call       class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags,
                                                                                                                                                                             string)
  IL_0041:  stelem.ref
  IL_0042:  ldloc.0
  IL_0043:  ldc.i4.3
  IL_0044:  ldc.i4.0
  IL_0045:  ldnull
  IL_0046:  call       class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags,
                                                                                                                                                                             string)
  IL_004b:  stelem.ref
  IL_004c:  ldloc.0
  IL_004d:  call       class [System.Core]System.Runtime.CompilerServices.CallSiteBinder [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.Binder::InvokeMember(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags,
                                                                                                                                                               string,
                                                                                                                                                               class [mscorlib]System.Collections.Generic.IEnumerable`1<class [mscorlib]System.Type>,
                                                                                                                                                               class [mscorlib]System.Type,
                                                                                                                                                               class [mscorlib]System.Collections.Generic.IEnumerable`1<class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)
  IL_0052:  call       class [System.Core]System.Runtime.CompilerServices.CallSite`1<!0> class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`5<class [System.Core]System.Runtime.CompilerServices.CallSite,class [mscorlib]System.Type,string,object,object>>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)
  IL_0057:  stsfld     class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`5<class [System.Core]System.Runtime.CompilerServices.CallSite,class [mscorlib]System.Type,string,object,object>> DuckTyping.Program/'<doQuack>o__SiteContainer2'::'<>p__Site3'
  IL_005c:  ldsfld     class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`5<class [System.Core]System.Runtime.CompilerServices.CallSite,class [mscorlib]System.Type,string,object,object>> DuckTyping.Program/'<doQuack>o__SiteContainer2'::'<>p__Site3'
  IL_0061:  ldfld      !0 class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`5<class [System.Core]System.Runtime.CompilerServices.CallSite,class [mscorlib]System.Type,string,object,object>>::Target
  IL_0066:  ldsfld     class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`5<class [System.Core]System.Runtime.CompilerServices.CallSite,class [mscorlib]System.Type,string,object,object>> DuckTyping.Program/'<doQuack>o__SiteContainer2'::'<>p__Site3'
  IL_006b:  ldtoken    [mscorlib]System.Console
  IL_0070:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
  IL_0075:  ldstr      "Dynamic: {0} says {1}"
  IL_007a:  ldsfld     class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>> DuckTyping.Program/'<doQuack>o__SiteContainer2'::'<>p__Site4'
  IL_007f:  brtrue.s   IL_00b3
  IL_0081:  ldc.i4.0
  IL_0082:  ldstr      "GetType"
  IL_0087:  ldnull
  IL_0088:  ldtoken    DuckTyping.Program
  IL_008d:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
  IL_0092:  ldc.i4.1
  IL_0093:  newarr     [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
  IL_0098:  stloc.1
  IL_0099:  ldloc.1
  IL_009a:  ldc.i4.0
  IL_009b:  ldc.i4.0
  IL_009c:  ldnull
  IL_009d:  call       class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags,
                                                                                                                                                                             string)
  IL_00a2:  stelem.ref
  IL_00a3:  ldloc.1
  IL_00a4:  call       class [System.Core]System.Runtime.CompilerServices.CallSiteBinder [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.Binder::InvokeMember(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags,
                                                                                                                                                               string,
                                                                                                                                                               class [mscorlib]System.Collections.Generic.IEnumerable`1<class [mscorlib]System.Type>,
                                                                                                                                                               class [mscorlib]System.Type,
                                                                                                                                                               class [mscorlib]System.Collections.Generic.IEnumerable`1<class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)
  IL_00a9:  call       class [System.Core]System.Runtime.CompilerServices.CallSite`1<!0> class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)
  IL_00ae:  stsfld     class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>> DuckTyping.Program/'<doQuack>o__SiteContainer2'::'<>p__Site4'
  IL_00b3:  ldsfld     class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>> DuckTyping.Program/'<doQuack>o__SiteContainer2'::'<>p__Site4'
  IL_00b8:  ldfld      !0 class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>>::Target
  IL_00bd:  ldsfld     class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>> DuckTyping.Program/'<doQuack>o__SiteContainer2'::'<>p__Site4'
  IL_00c2:  ldarg.0
  IL_00c3:  callvirt   instance !2 class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>::Invoke(!0,
                                                                                                                                                    !1)
  IL_00c8:  ldsfld     class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>> DuckTyping.Program/'<doQuack>o__SiteContainer2'::'<>p__Site5'
  IL_00cd:  brtrue.s   IL_0101
  IL_00cf:  ldc.i4.0
  IL_00d0:  ldstr      "Quack"
  IL_00d5:  ldnull
  IL_00d6:  ldtoken    DuckTyping.Program
  IL_00db:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
  IL_00e0:  ldc.i4.1
  IL_00e1:  newarr     [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
  IL_00e6:  stloc.2
  IL_00e7:  ldloc.2
  IL_00e8:  ldc.i4.0
  IL_00e9:  ldc.i4.0
  IL_00ea:  ldnull
  IL_00eb:  call       class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags,
                                                                                                                                                                             string)
  IL_00f0:  stelem.ref
  IL_00f1:  ldloc.2
  IL_00f2:  call       class [System.Core]System.Runtime.CompilerServices.CallSiteBinder [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.Binder::InvokeMember(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags,
                                                                                                                                                               string,
                                                                                                                                                               class [mscorlib]System.Collections.Generic.IEnumerable`1<class [mscorlib]System.Type>,
                                                                                                                                                               class [mscorlib]System.Type,
                                                                                                                                                               class [mscorlib]System.Collections.Generic.IEnumerable`1<class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)
  IL_00f7:  call       class [System.Core]System.Runtime.CompilerServices.CallSite`1<!0> class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)
  IL_00fc:  stsfld     class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>> DuckTyping.Program/'<doQuack>o__SiteContainer2'::'<>p__Site5'
  IL_0101:  ldsfld     class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>> DuckTyping.Program/'<doQuack>o__SiteContainer2'::'<>p__Site5'
  IL_0106:  ldfld      !0 class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>>::Target
  IL_010b:  ldsfld     class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>> DuckTyping.Program/'<doQuack>o__SiteContainer2'::'<>p__Site5'
  IL_0110:  ldarg.0
  IL_0111:  callvirt   instance !2 class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>::Invoke(!0,
                                                                                                                                                    !1)
  IL_0116:  callvirt   instance void class [mscorlib]System.Action`5<class [System.Core]System.Runtime.CompilerServices.CallSite,class [mscorlib]System.Type,string,object,object>::Invoke(!0,
                                                                                                                                                                                           !1,
                                                                                                                                                                                           !2,
                                                                                                                                                                                           !3,
                                                                                                                                                                                           !4)
  IL_011b:  ret
} // end of method Program::doQuack

Sin entrar a mirar qué hace el código, podemos imaginar que entre 14 y 130 líneas de código debe haber alguna diferencia de rendimiento.

Interfaces y librerías para Duck Typing

Cuando desarrollas en unos cuantos lenguajes siempre echas de menos cosas de uno y de otro en el que estás utilizando en ese momento. Cuando paso de JavaScript a C# no suelo echar muchas cosas de menos, pero un sistema de duck-typing o structural-typing si que vendría muy bien, sobre todo cuando utilizas clases anónimas que tienes que devolver a alguien.

public interface IProcess
{
    string Name { get; set; }
    int Id { get; set; }
}
static void Main(string[] args)
{
    var procList = (from x in System.Diagnostics.Process.GetProcesses().AsQueryable()
            select new { Name = x.ProcessName, Id = x.Id }).ToList();
    printProcList(procList);
}

private static void printProcList(List<IProcess> procList)
{
    procList.ForEach((p) => Console.WriteLine("{0}: {1}", p.Id, p.Name));
}

El código anterior no funciona, porque tendremos que crear una clase que implemente el interfaz y rellenarla con los datos que nos llegan. En nuestro caso podríamos hacerlo, pero a veces no nos es posible pues usamos librerías complicadas de las que no tenemos el código o si lo tenemos tampoco le podemos meter mucha mano.

Si queremos forzar duck typing en C# contra métodos que no están pensados para duck typing inicialmente, existen algunas librerías para poder hacer esto en nuestras aplicaciones .Net, aunque pueden penalizar mucho el rendimiento. Una de ellas es impromptu que nos permite hacer cosas como usar un tipo anónimo y convertirlo a un interfaz para poder utilizarlo en la aplicación:

    using ImpromptuInterface;

    public interface ISimpleClassProps
    {
        string Prop1 { get;  }

        long Prop2 { get; }

        Guid Prop3 { get; }
    }

...

    var tAnon = new {Prop1 = "Test", Prop2 = 42L, Prop3 = Guid.NewGuid()};

    var tActsLike = tAnon.ActLike<ISimpleClassProps>();

Como ya sabréis, los interfaces explícitos nos proporcionan una forma de comprobar en tiempo de compilación que un objeto cumple con una firma en concreto, pero eso también nos limita mucho, sobre todo con el uso de clases anónimas, pues estas no pueden implementar un interfaz. Para solucionar ésto algunos lenguajes han añadido el concepto de Structural Typing, que permite el uso de interfaces implícitos, pero que el compilador podrá comprobar, al contrario que lo que ocurre con duck typing.

Al final, creo que en el propósito de aprender un nuevo lenguaje cada año, este va a ser alguno con Structural Typing… a ver si conseguimos que lo añadan a C# algún día.

Enlaces interesantes sobre duck-typing y C#:

¿Como esperar con await en una expresión lambda?

Hoy he necesitado escribir un código dentro de una lambda que llamaba a métodos asíncronos. Normalmente estamos acostumbrados a marcar métodos asíncronos con la palabra async y ya podemos usar await a diestro y siniestro, pero ¿cómo se hace con una lambda? Pues en realidad igual, marcando la lambda con async:

Task.Factory.StartNew(async () =>
{
    await Task.Delay(1000);
});

Y por supuesto, la función lambda también es awaitable:

Func<Task<string>> t = async () =>
{
    await Task.Delay(1000);
    return "Hello";
};
System.Diagnostics.Debug.WriteLine(await t());

Por cierto, id con cuidado con ésto último que he hecho, poner un await como argumento, pues puede que nos llevemos alguna sorpresa… pero ya os lo cuento en otro mini-post.

Mejorar el rendimiento del canvas HTML5 desde C#

IMG_4102
Desarrollar aplicaciones para la Tienda Windows en JavaScript tiene sus ventajas e inconvenientes. Aunque en la mayoría de los casos no lo vamos a notar, cuando tratamos grandes cantidades de datos y tenemos que realizar modificaciones sobre estas, lo más probable es que se penalice el rendimiento.

Estoy desarrollando la nueva versión de Fingerpaint y quiero añadir una herramienta de relleno de color.
No es complicado de hacer, hay bastantes algoritmos bien optimizados y el context tiene los métodos getImageData y putImageData que nos dan el array de datos para modificar el contenido del canvas a nivel de pixel:

width = context.canvas.width;
height = context.canvas.height;
imageData = context.getImageData(0, 0, width, height);
data = imageData.data;
for(var i=0;i<data.length;i++){
  //tratar los píxeles de data uno por uno
}

El problema de hacer esto en JavaScript es que el lenguaje no está optimizado para este tipo de operaciones e intentar hacer un relleno un poco inteligente (estilo cubo de pintura) va a tardar mucho más de lo que estamos acostumbrados con cualquier aplicación de dibujo moderna.

Componentes Windows Runtime (WinRT)

Por suerte, mi aplicación FingerPaint es para Windows 8 (en realidad 8.1) y puedo usar librerías desarrolladas en otros lenguajes, como C# o C++, que me permitirán realizar estas operaciones mucho más rápido.
Es muy fácil tener código en otros lenguajes dentro de una aplicación JavaScript de la tienda Windows, sólo tenemos que añadir una nueva librería de tipo Windows Runtime Component en el lenguaje que prefiramos. Con este tipo de proyectos estamos indicando que es una librería que puede utilizarse desde cualquier otro lenguaje.

Lo que estamos haciendo es crear una librería con WinMD, el mismo sistema de metadatos que las librerías de sistema en Windows Runtime. En esta imagen creamos un nuevo componente en C#:
Windows Runtime Component

A continuación tenéis el ejemplo de código. Está dividido en dos métodos:

public sealed class Fill
{
   private byte[] _data;

   public void BeginFill(int x, int y, int width, int height, 
       [ReadOnlyArray] byte[] bitmap, string hexColor, byte tolerance)
   {
     _data=bitmap;
     //
     //aquí irá mi código de flood fill que modificará los datos
     //dentro de _data, pero al ser ReadOnly no volverán a JavaScript
     //modificados.
     //
   }

   public void EndFill([WriteOnlyArray] byte[] target)
   {
     _data.CopyTo(target,0);
   }
}

Si os fijáis, la clase es sealed y los parámetros array están decorados con los atributos Read/WriteOnlyArray. Estas dos características son requisito indispensable para que nuestra clase y métodos se puedan utilizar desde cualquier otro lenguaje.

Añadiremos el proyecto que hemos creado en las referencias de nuestra aplicación JavaScript y desde el código JavaScript las llamadas se verán así, como si fueran llamadas a cualquier otra librería JavaScript, pero tú y yo sabemos que está hecho en C#:

width = context.canvas.width;
height = context.canvas.height;
imageData = context.getImageData(0, 0, width, height);
data = imageData.data;
//creamos un objeto Fill
var helper=new ImageHelpers.Fill();
//calculamos el fill
helper.beginFill(x,y,width,height,data,"#00ff00",50);
//escribimos el resultado en imageData
helper.endFill(data);
//escribimos el resultado en el canvas
context.putImageData(imageData, 0, 0);

Para poder modificar el canvas necesitamos que nuestro método externo modifique directamente el array obtenido con getImageData, pero cuando trabajamos con componentes de WinRT y queremos pasar un array sólo podemos hacerlo en uno de estos dos modos:

  • ReadOnlyArray: trabajamos sobre una copia del array y cualquier modificación no se traspasará entre los contextos, ni siquiera si devolvemos el array como valor de retorno
  • WriteOnlyArray: podemos escribir sobre el array original… pero este siempre viene vacío, no veremos la información original

Adicionalmente, canvas no nos permite introducir un array de datos dentro de imageData que no haya sido creado por el propio canvas, así que si utilizáramos un parámetro de retorno tendríamos que copiar uno por uno los bytes del array, con lo que perderíamos el rendimiento que ganamos por hacerlo en C#.
Entonces, y por eso el artículo de hoy, tenemos que realizar la operación en dos pasos: en el primero obtenemos los datos originales y en el segundo escribimos sobre la memoria del canvas desde C#. Estas operaciones son bastante rápidas y casi no penalizan el rendimiento (entre 1 y 3 milisegundos en un i5), así que nos queda bastante margen para modificar el contenido del canvas y mejorar considerablemente la velocidad del fill con nuestro método C#.

Depuración híbrida

Para poder depurar nuestro código C# dentro de una aplicación JavaScript tendremos que indicar en las propiedades del proyecto qué tipo de lenguaje queremos depurar, a alguien se le olvidó poner Managed+Script así que por ahora sólo podremos depurar en uno o en otro, si hubiéramos elegido C++ como lenguaje no tendríamos este problema, pero tendríamos otros :P.
Script or Managed debug

Happy finger painting!

Usar SQLite en Apps Windows 8.1

Cuando necesitamos guardar datos estructurados que acostumbramos a tener en una base de datos, tenemos unas cuantas alternativas, entre ellas usar SQLite, una librería que incluye un motor SQL sobre un archivo del disco, con relaciones, índices, transacciones e incluso consultas estilo LINQ.

SQLite es una librería nativa, pero gracias a Visual Studio, NuGet y a los desarrolladores de la librería, será muy fácil integrarlo en nuestra aplicación.

Cómo agregar SQLite en nuestra App

El primer paso será descargar el paquete de librerías preparado para Windows Runtime 8.1 de la página de descargas de SQLite.
Debemos buscar el paquete para WinRT 8.1 en la sección Precompiled Binaries for Windows Runtime. Es un archivo .VSIX que podremos instalar como paquete en el Visual Studio.
La versión que he utilizado para este artículo es la 3.8.2 que podéis descargar aquí.

SQLite VSIX

Una vez instalado, en nuestro proyecto C# o VB.Net de la Tienda Windows, añadiremos la referencia a la librería SQLite. Podemos encontrarla en Windows>Extensions:

SQLite Windows Runtime Libraries

Este paquete nos incluirá la librería SQLite 3, pero esta librería es nativa y no se puede utilizar directamente desde C# o VB.Net. Para empezar a usarla necesitaremos una clase que encapsule las llamadas. Por suerte ya está hecha, basta descargar sqlite-net a través de NuGet:

sqlite-net NuGet Package

Este paquete instala dos archivos c# que nos hacen de puente con la librería y nos permiten ejecutar consultas contra una base de datos sqlite:
sqlite.cs

Ejemplo de uso

Ya sólo nos queda crear una base de datos, empezar a grabar y a consultar datos. Como es un archivo local, tendremos que copiar una .db existente o bien crear una dentro del sistema de archivos de la aplicación (nos sirven tanto la carpeta temporal como la local). Aquí vemos un pequeño ejemplo de definición, creación e inserción.

public class Person{
    [SQLite.PrimaryKey,SQLite.AutoIncrement]
    public int Id { get; set; }

    [SQLite.MaxLength(50)]
    public string Name { get; set; }

    [SQLite.MaxLength(50)]
    public string Surname { get; set; }

}

private async void createDB()
{
    var folder = Windows.Storage.ApplicationData.Current.LocalFolder;
    var conn = new SQLite.SQLiteAsyncConnection(
        System.IO.Path.Combine( folder.Path,"test.db"));
    
    await conn.CreateTableAsync<Person>();            
}

private async Task insertPersonAsync(string name, string surname)
{
    var folder = Windows.Storage.ApplicationData.Current.LocalFolder;
    var conn = new SQLite.SQLiteAsyncConnection(
        System.IO.Path.Combine(folder.Path, "test.db"))
    await conn.InsertAsync(new Person { Name = name, Surname = surname });
}

Binding a imágenes de carpetas especiales en Windows 8

Descarga el código de este artículo en Codeplex

Hoy para cambiar un poco haré un ejemplo en XAML/C#, pero seguimos con aplicaciones de la tienda Windows.
Os explicaré un truco que se puede realizar de dos formas: la primera, la forma automática, utilizando una clase del sistema que ya nos hace casi todo el trabajo y la segunda, una forma manual de realizarlo, que dejaremos para más adelante.

Las carpetas especiales

En las aplicaciones de la Tienda Windows podemos acceder directamente a algunas carpetas especiales del sistema siempre que declaremos en el manifiesto que queremos acceder y el usuario lo sepa:
pictureslibrary
Una vez hemos establecido el requisito en el manifiesto, ya podemos utilizar la clase Windows.Storage.KnownFolders para listar los elementos de la carpeta de imágenes:

var queryOptions = new Windows.Storage.Search.QueryOptions();
queryOptions.FolderDepth = FolderDepth.Deep;
var query = KnownFolders.PicturesLibrary.CreateFileQueryWithOptions(queryOptions);

Nota: si intentáis esto en otra carpeta, como por ejemplo “Mis Documentos”, no funcionará, pues también hay que declarar que tipos de archivo vamos a abrir y sólo podremos abrir esos.

Listar todos los archivos dentro de la carpeta

Para obtener una lista de todos los archivos podemos llamar al método GetFilesAsync() y luego podremos trabajar sobre la misma. Si vamos a representar esa lista en el interfaz de usuario, WinRT nos ofrece una forma mucho mejor: podemos obtener una lista virtualizada, esto es, una lista con el mismo número de elementos que contiene la carpeta y las características de esos elementos se van obteniendo de forma asíncrona. De esta forma obtendremos los primeros resultados mucho más rápido y veremos en nuestra colección en pantalla el tamaño completo de la lista, aunque todavía no se hayan obtenido todos los resultados.

public class DataSource:INotifyPropertyChanged
{
    object _items;
    public object Items
    {
        get { return _items; }
        private set
        {
            _items = value;
            onPropertyChanged("Items");
        }
    }

    public DataSource()
    {
        try
        {
            var queryOptions = new Windows.Storage.Search.QueryOptions();
            queryOptions.FolderDepth = FolderDepth.Deep;
            var query = KnownFolders.PicturesLibrary.CreateFileQueryWithOptions(queryOptions);
            var fileInformationFactory = new FileInformationFactory(query,
                Windows.Storage.FileProperties.ThumbnailMode.PicturesView,
                150, Windows.Storage.FileProperties.ThumbnailOptions.UseCurrentScale, true);
            Items = fileInformationFactory.GetVirtualizedFilesVector();
        }
        catch (Exception ex)
        {
            Items = new object[] {new{ Name = ex.Message} };
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void onPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

Si observamos el código, veremos que la clase FileInformationFactory nos permite generar también una vista previa de cada uno de los archivos. El método no es asíncrono, esto quiere decir que nos devolverá muy rápidamente un resultado: la lista virtualizada llena de elementos vacíos, que luego se irán rellenando en segundo plano.

Ahora sólo nos hace falta crear un contenedor GridView para mostrar los archivos:

<Page
    x:Class="ImageBinding.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:ImageBinding"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    xmlns:localData="using:ImageBinding.DataModel">
    <Page.Resources>
        <localData:DataSource x:Key="mainDataSource"></localData:DataSource>
        <CollectionViewSource Source="{Binding Path=Items, Source={StaticResource mainDataSource}}"
                              x:Key="mainView"></CollectionViewSource>
        <DataTemplate x:Key="DataTemplate">
            <Grid Width="150">
                <TextBlock Text="{Binding Name}" TextTrimming="WordEllipsis" ></TextBlock>
            </Grid>
        </DataTemplate>
    </Page.Resources>
    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}" 
        DataContext="{StaticResource mainDataSource}">
        <GridView
            Margin="0 90 0 0" ItemsSource="{Binding Source={StaticResource mainView }}" 
                  ItemTemplate="{StaticResource DataTemplate}" SelectionMode="None">
        </GridView>
    </Grid>
</Page>

Carga de imágenes

Una vez tenemos la lista de archivos vamos a mostrar las imágenes que os prometí al principio del artículo. La colección que nos proporciona FileInformationFactory.GetVirtualizedFilesVector() contiene elementos que cumplen con el interfaz IStorageItemInformation. Estos elementos tienen una propiedad Thumbnail a la que podremos enlazarnos para visualizar la imagen, pero no podremos hacerlo directamente pues el tipo StorageItemThumbnail en realidad es un tipo Stream y no una imagen, así que necesitaremos un Converter para poder utilizar la imagen dentro del interfaz de usuario:

public class StreamToBitmapConverter:IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        if (value != null)
        {
            var stream = (IRandomAccessStream)value;
            var img = new BitmapImage();
            img.SetSource(stream);
            return img;
        }
        return null;
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        throw new NotImplementedException();
    }
}

A través del Converter ya podremos hacer el enlace correctamente:

<Page.Resources>
    <localData:DataSource x:Key="mainDataSource"></localData:DataSource>
    <CollectionViewSource Source="{Binding Path=Items, Source={StaticResource mainDataSource}}"
                          x:Key="mainView"></CollectionViewSource>
    <localConverters:StreamToBitmapConverter x:Key="bitmapConverter"/>
    <DataTemplate x:Key="DataTemplate">
        <Grid Width="150">
            <Grid.RowDefinitions>
                <RowDefinition Height="70"/>
                <RowDefinition Height="32"/>    
            </Grid.RowDefinitions>
            <Image Grid.RowSpan="2" Source="{Binding Thumbnail, 
                Converter={StaticResource bitmapConverter}}"></Image>
            <Border Grid.Row="1" Background="#80000000" Padding="5">
                <TextBlock Text="{Binding Name}" VerticalAlignment="Center" 
                           TextTrimming="WordEllipsis" />
            </Border>
        </Grid>
    </DataTemplate>
</Page.Resources>

Y aquí tenemos el resultado:
picturesCollection
En el próximo artículo os contaré cómo hacer lo mismo pero programando nosotros la carga asíncrona de imágenes bajo demanda.

Descarga el código de este artículo en Codeplex

Recursos útiles para aprender a programar en WP7

Muchos de los que habéis estado en las últimas presentaciones de Windows Phone 7 nos habéis preguntado sobre qué recursos hay disponibles para aprender a programar para el dispositivo y cual sería el camino de aprendizaje.

Como ya sabéis, en el App Hub hay mucha documentación y laboratorios para empezar a programar en WP7, aunque a veces nos podemos perder entre tanto material. Yo recomiendo empezar por la base, el lenguaje C#, y luego continuar con algún buen libro de Windows Phone que se pueda seguir de principio a fin. Aquí tenéis enlaces a algunos libros muy útiles que os podéis descargar. La ruta de aprendizaje habitual es C#, Silverlight y XNA, al que habría que añadir algo de programación en la nube para tener una base sobre el almacenamiento y la computación en la nube, por si vamos a utilizar datos en nuestra aplicación.

Estos libros son gratuitos, pero están en inglés. Para los que prefieran tener algo en castellano, en el MSDN tenéis estupendos recursos para aprender C#, Windows Phone 7 y Azure, y también son gratuitos:

Además tenemos el grupo de Desarrolladores de Windows Phone 7 en LinkedIn, donde podréis manteneros informados.

Nos vemos en los próximos eventos!