├── README.md ├── LICENSE ├── hola.workbook └── index.workbook └── linq4.workbook /README.md: -------------------------------------------------------------------------------- 1 | # guoerbucs 2 | Algunos ejemplos de Workbooks de Xamarin. 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 That C# Guy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /hola.workbook/index.workbook: -------------------------------------------------------------------------------- 1 | --- 2 | uti: com.xamarin.workbook 3 | platforms: 4 | - Console 5 | packages: 6 | - id: Newtonsoft.Json 7 | version: 9.0.1 8 | - id: Microsoft.Net.Http 9 | version: 2.2.29 10 | - id: Microsoft.Bcl 11 | version: 1.1.10 12 | --- 13 | 14 | # Bienvenido a los Xamarin Workbooks 15 | 16 | Con ellos, aprender a programar a .NET cobra un nuevo significado. Mira, por ejemplo, cómo se ve un “Hola mundo“ en ellos: 17 | 18 | ```csharp 19 | Console.WriteLine("Hola mundo"); 20 | ``` 21 | 22 | ### Interfaz 23 | 24 | Vamos a ver algunos elementos de la interfaz antes de adentrarnos de lleno en el tema. Estos son los controles que te encontrarás muy seguido: 25 | 26 | ![](http://i.imgur.com/LujKEPN.png "Interfaz") 27 | 28 | Con el símbolo de `+` puedes agregar un nuevo bloque de código, con el de `”` puedes agregar un bloque de texto y con el de `✖️` puedes eliminar el bloque seleccionado. 29 | 30 | Otro de los elementos con los que seguramente estarás muy familiarizado es el *Intellisense*: 31 | 32 | ![](http://i.imgur.com/V6LUPYh.png "Intellisense") 33 | 34 | ### Declaración de variables 35 | 36 | También podemos declarar variables y asignarlas para el documento: 37 | 38 | ```csharp 39 | int entero; // declaración 40 | float flotante = 10f; // Asignación 41 | decimal x = (decimal)flotante * 3; 42 | decimal y = x / 6; 43 | ``` 44 | 45 | ### Declaración de clases 46 | 47 | Inclusive podemos crear clases completas 48 | 49 | ```csharp 50 | public class Pokemon 51 | { 52 | public int Id { get; set; } 53 | public string Name { get; set; } 54 | public int Height { get; set; } 55 | public int Weight { get; set; } 56 | } 57 | ``` 58 | 59 | Y luego, instanciarlas: 60 | 61 | ```csharp 62 | var p1 = new Pokemon(); 63 | p1.Name = "Pikachu"; 64 | ``` 65 | 66 | ### NuGet 67 | 68 | Oh, y también puedes insertar paquetes de *NuGet*, para hacerlo, tienes que ir a la barra de menús `Archivo > Agregar paquetes` y listo. Por ejemplo, en este Workbook agregué los paquetes de las librerías HTTP de Microsoft y Newtonsoft.Json para manipular este formato. Vamos a consultar la PokéAPI 69 | 70 | Una vez agregado el paquete aparecerán unas directivas para preprocesador que le indican al Wokbook que haremos uso de dichos paquetes: 71 | 72 | ```csharp 73 | #r "System.Net.Http.Primitives" 74 | #r "System.Net.Http.Extensions" 75 | #r "Newtonsoft.Json" 76 | ``` 77 | 78 | A partir de entonces podemos hacer uso de estas, ¡pero hey! no olvides los `using` 79 | 80 | ```csharp 81 | using Newtonsoft; 82 | using System.Net.Http; 83 | using System.Net.Http.Headers; 84 | ``` 85 | 86 | Ahora sí, vamos a consultar la PokéAPI. Configuramos el cliente: 87 | 88 | ```csharp 89 | var client = new HttpClient(); 90 | client.BaseAddress = new Uri("http://pokeapi.co/api/v2/"); 91 | client.DefaultRequestHeaders.Accept.Clear(); 92 | client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); 93 | ``` 94 | 95 | Y realizamos las llamadas. ¿por qué no buscas a tu Pokémon favorito modificando la variable `pkmn`? (no olvides presionar ctrl o cmd \+ ↩︎ para ejecutar el código: 96 | 97 | ```csharp 98 | var pkmn = "jirachi"; 99 | var response = await client.GetAsync("pokemon/" + pkmn); 100 | ``` 101 | 102 | ¡Oh! lo olvidaba, ¿ves eso que sale debajo de nuestro código cada vez que lo ejecutamos? no es nada más que otra de las maravillas de los Workbooks, que realiza la evaluación de la última expresión y la presenta en pantalla, además de que nos da varias opciones para visualizar la información: 103 | 104 | Ahora sí, de vuelta al código: 105 | 106 | ```csharp 107 | if(response.IsSuccessStatusCode) 108 | { // ... Read the string. 109 | string result = await response.Content.ReadAsStringAsync(); 110 | var poke = await Newtonsoft.Json.JsonConvert.DeserializeObjectAsync(result); 111 | Console.WriteLine($"{poke.Id:000} {poke.Name}: H: {poke.Height} and W: {poke.Weight}"); 112 | } 113 | ``` 114 | 115 | ### ¿Cómo son los Workbooks? 116 | 117 | Por si mismos, los Workbooks no son más que archivos te texto plano (un híbrido entre YAML, Markdown y otra cosa) que son interpretados por la aplicación de escritorio. 118 | 119 | Vamos a revisar precisamente este mismo archivo. Estas son las primeras líneas: 120 | 121 | ![](http://i.imgur.com/1xb3xPm.png "Primeras líneas de un Workbook") 122 | 123 | La primera es un *Uniform Type Identifier*, la segunda es la especificación de para qué plataformas es nuestro espacio de trabajo (en este caso es la consola) y por último la declaración de los paquetes de los que se hace uso. 124 | 125 | Otra cosa que podemos revisar es la forma en la que los bloques de código se especifican, es muy parecido a cuando se declaran en markdown, con la diferencia de que tiene un `csharp` después de las tildes invertidas: 126 | 127 | ![](http://i.imgur.com/ac1OWU9.png "Bloque de código C#") 128 | 129 | Lo cierto es que varias veces le tuve que meter las manos al código fuente del archivo para lograr algunas cosas en este archivo, pero vamos, que apenas es la primera versión “estable“ de esta herramienta. 130 | 131 | ## Instalación 132 | 133 | Si ya estás ansioso por descargar y probar los Workbooks puedes dirigirte a [este enlace.](https://developer.xamarin.com/guides/cross-platform/workbooks/install/ "Xamarin Workbooks") 134 | 135 | ## Usos 136 | 137 | Seguramente ya estarás pensando en algún uso para esta nueva herramienta. El más claro que yo tengo en mente es el poder los posts de [#AprendeCSharp](http://thatcsharpguy.com/tag/AprendeCSharp/ "Tag #AprendeCSharp"), es más, ¿por qué no comienzas por [descargar este o los que Xamarin preparó para ti?](http://thatcsharpguy.com/tag/AprendeCSharp/ "Descarga este Workbook") 138 | 139 | Eso es todo por este post, espero descarguen los Xamarin Workbooks y los usen como una herramienta para aprender. -------------------------------------------------------------------------------- /linq4.workbook: -------------------------------------------------------------------------------- 1 | --- 2 | uti: com.xamarin.workbook 3 | platforms: 4 | - Console 5 | --- 6 | Antes de comenzar con el post vamos a declarar algunos métodos y clases que estaremos usando para los ejemplos que veremos más adelante. 7 | 8 | Vamos a necesitar dos métodos utilitarios para imprimir colecciones de datos: 9 | 10 | ```csharp 11 | void PrintInline(IEnumerable collection) 12 | { 13 | var enumerator = collection.GetEnumerator(); 14 | while(enumerator.MoveNext()) 15 | { 16 | Console.Write(enumerator.Current); 17 | Console.Write(" "); 18 | } 19 | Console.WriteLine(); 20 | } 21 | 22 | void Print(IEnumerable collection) 23 | { 24 | var enumerator = collection.GetEnumerator(); 25 | while(enumerator.MoveNext()) 26 | Console.WriteLine(enumerator.Current); 27 | } 28 | 29 | class Persona 30 | { 31 | public string Nombre { get; set; } 32 | public string Apellido { get; set; } 33 | public override string ToString() { return Apellido + ", " + Nombre; } 34 | public override bool Equals(object o) 35 | { 36 | var oth = o as Persona; 37 | if(oth != null) 38 | return oth.Apellido.Equals(Apellido); 39 | return false; 40 | } 41 | 42 | public override int GetHashCode() 43 | { 44 | return Apellido.GetHashCode(); 45 | } 46 | } 47 | 48 | var coleccion3 = Enumerable.Range(10, 6); 49 | var coleccion4 = Enumerable.Range(16, 6); 50 | PrintInline(coleccion3); 51 | PrintInline(coleccion4); 52 | 53 | var nombres = new String[] { "A", "B", "A", "C", "D", "A" }; 54 | var apellidos = new String[] { "Z", "X", "Y", "Y", "W", "Z" }; 55 | ``` 56 | 57 | Listo, más adelante verás por qué sobreescribimos esos dos métodos. Ahora si, comencemos con Linq: 58 | 59 | ## Zip 60 | El método Zip nos ayuda para cuando queremos combinar dos colecciones de datos en el orden en el que estan. Con Zip tu especificas la forma en las que se deben combinar, por ejemplo en la siguiente linea se combinan dos series numéricas, multiplicando cada elemento entre si: 61 | 62 | ```csharp 63 | var coleccion1 = new int [] { 0, 1, 2, 3, 4, 5 }; 64 | var coleccion2 = new int [] { 4, 5, 6, 7, 8, 9 }; 65 | 66 | var combinados = coleccion1.Zip(coleccion2, (a, b) => a * b); 67 | PrintInline(combinados); 68 | ``` 69 | 70 | También se pueden combinar cadenas, como las de nombres y apellidos para crear un objeto de la clase Persona: 71 | 72 | ```csharp 73 | var nombres = new String[] { "A", "B", "A", "C", "D", "A" }; 74 | var apellidos = new String[] { "Z", "X", "Y", "Y", "W", "Z" }; 75 | 76 | var personas = nombres.Zip(apellidos, (n, a) => new Persona { Nombre= n, Apellido = a}).OrderBy(p => p.Apellido); 77 | var otrasPersonas = nombres.Zip(apellidos.Reverse(), (n, a) => new Persona { Nombre= n, Apellido = a}).OrderBy(p => p.Apellido); 78 | Print(personas); 79 | Print(otrasPersonas); 80 | ``` 81 | 82 | ## Equals, GetHashCode & IEqualityComparer 83 | En los siguientes métodos vamos a requerir de una forma de discernir si dos instancias de una misma clase son las mismas o no (y es por eso que sobreescribimos `Equals` y `GetHashCode`), sin embargo no siempre tendremos acceso a las "entrañas" de una clase para sobrescribir sus métodos o simplemente queremos tener otra forma de comparar dos objetos. Para estos casos podemos usar una implementación de la interfaz `IEqualityComparer`, por ejemplo, la siguente clase nos ayudará a distinguir una `Persona` de otra únicamente por su nombre: 84 | 85 | ```csharp 86 | class NameEqualityComparer : IEqualityComparer 87 | { 88 | public bool Equals(Persona x, Persona y) => x.Nombre.Equals(y.Nombre); 89 | public int GetHashCode(Persona obj) => obj.Nombre.GetHashCode(); 90 | } 91 | ``` 92 | 93 | ## Union 94 | Con `Union` se juntan dos colecciones de datos, es importante que se diferencíe este método de Concat, ya que mientras que uno junta las dos colecciones sin preocuparse del contenido de estas, Union no permite que existan duplicados en la colección resultante: 95 | 96 | ```csharp 97 | var concatenados = coleccion1.Concat(coleccion2); 98 | var unidos = coleccion1.Union(coleccion2); 99 | PrintInline(concatenados); 100 | PrintInline(unidos); 101 | ``` 102 | 103 | ## Intersect 104 | Es bastante obvio lo que realiza este método, intersecta dos colecciones, dando como resultado otra con solo los elementos que tienen en comun. Nuevamente, usa el método `Equals` (o `IEqualityComparer`) para decidir qué elementos se parecen y cuales no. 105 | 106 | ```csharp 107 | var interseccion = coleccion1.Intersect(coleccion2); 108 | PrintInline(interseccion); 109 | ``` 110 | 111 | ## Except 112 | Con `Except` podemos filtrar una colección basándonos en otra. En este caso los únicos elementos que forman parte de la nueva colección que existen en `coleccion1` que no existen en `coleccion2`: 113 | 114 | ```csharp 115 | var except = coleccion1.Except(coleccion2); 116 | PrintInline(except); 117 | ``` 118 | 119 | ## SequenceEquals 120 | Este método nos ayuda para saber si los elementos que contiene una colección existen en el mismo orden en otra. Si uno tiene menos, si un elemento es distinto o si están en diferente posición, este método devolverá false: 121 | 122 | Al igual los demás también este puede funcionar con una implementación de `IEqualityComparer`: 123 | 124 | ```csharp 125 | var secuencia1 = Enumerable.Range(0, 4); 126 | var secuencia2 = Enumerable.Range(0, 4); 127 | var secuencia3 = Enumerable.Range(1, 4); 128 | 129 | var sonIguales = secuencia1.SequenceEqual(secuencia2); 130 | Console.WriteLine("Son iguales " + sonIguales); 131 | 132 | var sonIguales1 = secuencia1.SequenceEqual(secuencia3); 133 | Console.WriteLine("Son iguales " + sonIguales1); 134 | ``` 135 | 136 | ## Distinct 137 | Como tal lo dice el nombre, con `Distnict` vamos a poder filtrar los elementos iguales de nuestra colección dejándonos con una que tiene elementos no repetidos entre si: 138 | 139 | Este método también acepta una implementación de `IEqualityComparer`: 140 | 141 | ```csharp 142 | var distintos = concatenados.Distinct(); 143 | PrintInline(distintos); 144 | 145 | var personasDistintas = personas.Distinct(); 146 | Console.WriteLine("Personas distintas por apellido"); 147 | Print(personasDistintas); 148 | 149 | var personasDistintasNombre = personas.Distinct(new NameEqualityComparer()); 150 | Console.WriteLine("Personas distintas por nombre"); 151 | Print(personasDistintasNombre); 152 | ``` 153 | 154 | ## All & Any 155 | Estos métodos nos ayudan a responder las preguntas: ¿alguno de los elementos cumple con la condición dada? y ¿todos los elementos cumplen con la condición dada? 156 | 157 | ```csharp 158 | bool todosDivisiblesEntre2 = secuencia1.All( i => i % 2 == 0); 159 | bool algunoDivisibleEntre2 = secuencia1.Any( i => i % 2 == 0); 160 | 161 | Console.WriteLine("Todos divisibles: " + todosDivisiblesEntre2); 162 | Console.WriteLine("Alguno divisible: " + algunoDivisibleEntre2); 163 | ``` 164 | 165 | ## Para terminar 166 | En el siguiente post hablaré de cómo podemos crear lenguajes específicos de dominio usando Linq y métodos de extensión. 167 | --------------------------------------------------------------------------------