[Whitepaper gratuito] Comenzando con Open Data Protocol

En el MIX de Las Vegas, ví las primeras demos y características de Open Data Protocol OData- de la mano de nada más y nada menos que de Pablo Castro y quede gratamente sorprendido pues redireccionaban el camino equivocado tomado hacia unos meses con Astoria. La verdad es que la idea inicial de Astoria era algo alentadora, pero no la puestra en práctica. La coletilla o pretexto de que OData era una evolución de Astoria, no decia mucho a su favor, en principio, pero despues de haberlo puesto en práctica en algunos determinados escenarios en mi actual empresa, estoy francamente satisfecho.

Si bien es cierto que la idea subyacente de Astoria prometía, a la práctica no fue así. Los orígenes de datos expuestos eran propietarios. No puedo admitir que fuera ni un experto ni un fan, tanto de EF como de Astoria, pero lo cierto es que el poco contacto q tuve con ambas tecnologias simultáneamente admito que la experiencia no fue positiva.

Entonces, ¿Que ha cambiado con OData? En primer lugar, Microsoft anuncia a través de Microsoft’s Open Specification Promise (OSP) la estandarización de la tecnología. En segundo lugar tratar de dar solución a la exposición de orígenes de datos, relacionales o no, a través de un Servicio Web ejecutando operaciones con un lenguaje “estándar” basandose en:

  • La creación de una forma uniforme de representación de datos estructurados a través de Atom o JSON (JavaScript Object Notation)
  • La utilización de convenciones URL uniformes tanto para la navegación, filtrado, orden y paginación de datos (entre otros)
  • La creación de operaciones uniformes dirigidas por dirección mediante las acciones GET, POST, PUT y DELETE.

En definitiva no OData no es más que una estandarización de la creación y consumo de datos via Web que está construido sobre un conjunto de estándares de Internet, espcialmente Atom Publishing Protocol o AtomPub especificado en RFD 5023 quien a su vez está sontruido sobre Atom Syndication Format o Atom especificado en RFC4287.

En este whitepaper he tratado de introducir la problemática y necesidades de la exposición de orígenes de datos con las tecnologias Web actuales y cómo OData soluciona parte de esas problemáticas. OData ofrece una gran variedad de operaciones sobre un conjunto de datos que nos aportan una mayor flexibilidad y optimización y por otra parte una alta integración con todo tipo de clientes:

  • Cualquier explorador Web
  • Apps .NET Framework 3.5/4.0
  • Silverlight 3/4
  • Windows Phone 7
  • Java / JavaScript
  • PHP
  • AJAX
  • Excel 2010 PowerPoint
  • LINQPad
  • SQL Azure

Además de mostrar cómo crear un servicio OData muestro varios ejemplos básicos sobre algunos de los cliente enumerados arriba. En definitiva, un Whitepaper que pretende presentar de una forma práctica Open Data Protocol a cualquier desarrollador y empezar a valorar la utilidad de esta nueva apuesta para nuestros desarrollos.

Recursos

- PDF/Libro electrónico

- Lectura OnLine

- Sigue los comentarios en la página de Facebook de CampusMVP

-Colecciones del ObjectModel- Coleccionando objetos en .NET Framework (III)

Introducción

Esta serie de artículos pretende mostrar las características y peculiaridades de las colecciones en .NET. El objetivo no es mostrar las situaciones en las que cada una de los diferentes tipos de colecciones pueden utilizarse en cada contexto sino la de conocer las mismas, ventajas y desventajas, para poder seleccionar el tipo de colección más apropiado en cada momento.

La serie cubre (entre corchetes el estado):

  • Colecciones No Genericas
  • Colecciones Genéricas System.Collections.Generic
  • Colecciones de System.Collections.ObjectModel (este post)
  • Colecciones nuevas en CLR 4.0 (no es definitivo además solo hay una)
  • Cota superior asintótica de las colecciones del CLI. aka Notación de Landau - O Grande- (en desarrollo)
  • Power Collections y C5 (por ahí andan)
  • Rx  (si hay ganas y tiempo)

Colecciones System.Collections.ObjectModel

Todas las colecciones agrupadas bajo System.Collections.ObjectModel tiene como denominador común que todas y cada una de ellas pueden ser utilizadas como modelo de objetos en librerias públicas con la intención de ser extendidas.

Krzysztof Cwalina expone sus razones por las cuales algunas de estas clases han sido clasificadas bajo dicho espacio de nombres en el siguiente post. Básicamente, la gran mayoria de desarrolladores nos conformaremos con utilizar las colecciones expuestas tanto en System.Collections como en System.Collections.Generics dejando las expuestas en ObjectModel las utilizadas en menor medidad para otros usos no tan habituales como es  la generacción de colecciones propietarias.

Dicho esto, lo que pretende este post es introducir las 5 clases con las que se presenta .NET Framework 4.0 y que son:

  • System.Collections.ObjectModel.Collection<T>
  • System.Collections.ObjectModel.KeyedCollection<TKey,TItem>
  • System.Collections.ObjectModel.ObservableCollection<T>
  • System.Collections.ObjectModel.ReadOnlyCollection<T>
  • System.Collections.ObjectModel.ReadOnlyObservableCollection<T>

System.Collections.ObjectModel.Collection<T>

Collection<T> se utiliza como clase base (pese a que no es abstracta) para la implementación de colecciones personalizadas. Para ello expone parte de sus métodos como virtuales, tales como ClearItems, InsertItem, RemoveItem y SetItem. Por lo tanto se recomienda que todo los desarroladores que pretendan generar una colección personalizada extiendan Collection<T> en lugar de crear una desde zero.

El propio .NET Framework hace un uso extensivo de Collection<T> en gran parte de las colecciones utilizadas:

System.Object
  System.Collections.ObjectModel.Collection<T>
    System.Collections.ObjectModel.KeyedCollection<TKey, TItem>
    System.Collections.ObjectModel.ObservableCollection<T>
    System.ComponentModel.BindingList<T>
    System.ComponentModel.SortDescriptionCollection
    System.Net.IPEndPointCollection
    System.Net.Mail.AlternateViewCollection
    System.Net.Mail.AttachmentCollection
    System.Net.Mail.LinkedResourceCollection
    System.Net.Mail.MailAddressCollection
    System.Net.PeerToPeer.CloudCollection
    System.Net.PeerToPeer.Collaboration.PeerApplicationCollection
    System.Net.PeerToPeer.Collaboration.PeerContactCollection
    System.Net.PeerToPeer.Collaboration.PeerEndPointCollection
    System.Net.PeerToPeer.Collaboration.PeerNearMeCollection
    System.Net.PeerToPeer.Collaboration.PeerObjectCollection
    System.Net.PeerToPeer.PeerNameRecordCollection
    System.Security.Cryptography.CngPropertyCollection
    System.ServiceModel.Channels.BindingElementCollection
    System.ServiceModel.Channels.ChannelParameterCollection
    System.ServiceModel.Description.FaultDescriptionCollection
    System.ServiceModel.Description.MessageDescriptionCollection
    System.ServiceModel.Description.OperationDescriptionCollection
    System.ServiceModel.Description.PolicyAssertionCollection
    System.ServiceModel.Description.ServiceEndpointCollection
    System.ServiceModel.Dispatcher.MessageQueryCollection
    System.ServiceModel.Syndication.SyndicationElementExtensionCollection
    System.Web.DynamicData.DataControlReferenceCollection
    System.Web.Routing.RouteCollection
    System.Web.UI.DataVisualization.Charting.ChartElementCollection<T>
    System.Web.UI.ScriptReferenceCollection
    System.Web.UI.ServiceReferenceCollection
    System.Web.UI.UpdatePanelTriggerCollection
    System.Windows.ConditionCollection
    System.Windows.Forms.DataVisualization.Charting.ChartElementCollection<T>
    System.Windows.Forms.FileDialogCustomPlacesCollection
    System.Windows.Ink.StrokeCollection
    System.Windows.Input.StylusPlugIns.StylusPlugInCollection
    System.Windows.Input.StylusPointCollection
    System.Windows.Input.TouchPointCollection
    System.Windows.SetterBaseCollection
    System.Windows.TriggerCollection
    System.Workflow.ComponentModel.Compiler.ValidationErrorCollection

System.Collections.ObjectModel.KeyedCollection<TKey,TItem>

Se trata de una clases abstracta que como peculiaridad las claves estan incrustadas en sus valores. Tal y como se define en el MSDN Library, KeyedCollection<TKey,TItem> es un conjunto infinito de tipos abstractos ya que la implementación dependerá en gran medida de los tipos genericos representados por TKey y TItem.

La clase KeyedCollection<TKey, TItem> es un híbrido entre una colección basada en IList<T> y una colección basada en IDictionary<TKey, TValue> y por tanto puede ser accedida mediante índice y clave. La diferencia fundamental es que ésta no es una par clave/valor ya que el propio valor agrupa tanto el valor en sí como la clave. Su firma es:

public abstract class KeyedCollection<TKey, TItem> : Collection<TItem>
{
    protected KeyedCollection();
    protected KeyedCollection(IEqualityComparer<TKey> comparer);
    protected KeyedCollection(IEqualityComparer<TKey> comparer, int dictionaryCreationThreshold);
    public IEqualityComparer<TKey> Comparer { get; }
    public TItem this[TKey key] { get; }
    protected IDictionary<TKey, TItem> Dictionary { get; }
    public bool Contains(TKey key);
    public bool Remove(TKey key);
    protected void ChangeItemKey(TItem item, TKey newKey);
    protected override void ClearItems();
    protected abstract TKey GetKeyForItem(TItem item);
    protected override void InsertItem(int index, TItem item);
    protected override void RemoveItem(int index);
    protected override void SetItem(int index, TItem item);
}

Por ejemplo, KeyedCollection<int, Empleado> puede contener una clave “234449” que pertenece como propiedad al propio elemento Empleado (como por ejemplo el código del mismo) que se obtendría a través del método abstracto GetKeyForItem() de la siguiente forma:

public class Departamento : KeyedCollection<int, Empleado>
{
    public Departamento () : base(null, 0) {}
 
    protected override int GetKeyForItem(Empleado empleado)
    {
        return empleado.Codigo;
    }
 
     //Clase incompleta
}

 

System.Collections.ObjectModel.ObservableCollection<T>

 http://msdn.microsoft.com/en-us/library/ms668604.aspx 

Las colecciones ObservableCollection<T> fueron una de las caracterísitcas más importantes introducidas a raíz de WPF y Silverlight posteriormente debido a la capacidad que tiene de propagar una modificación sobre el conjunto de elementos de la colección, a través de un par de interfaces que veremos a continuación, y que sirve como base para el Data Binding con los elementos o vistas WPF/Silverlight, por ejemplo.

Si observamos la firma de ObservableCollection<T> vemos que además de implementar la clase abstracta Collection<T>, implementa INotifyCollectionChanged e INotifyPropertyChanged.

[Serializable]
public class ObservableCollection<T> 
    : Collection<T>, INotifyCollectionChanged, INotifyPropertyChanged
{
...
}

Si vemos la definición de INotifyCollectionChanged:

public interface INotifyCollectionChanged
{
    event NotifyCollectionChangedEventHandler CollectionChanged;
}

Vemos que implementa un evento del tipo NotifyCollectionChangedEventHandler el cual notificará a los “subscriptores” – o listeners en inglés- ante cualquier modificación sobre el conjunto de elementos. Ojo, se utiliza la palabra subscriptores entre comillas pues no es una entorno publicador – subscriptor real. (Véase Observer Design Pattern with .NET)

Por otro lado, la interfaz INotifyPropertyChanged:

public interface INotifyPropertyChanged
{
    event PropertyChangedEventHandler PropertyChanged;
}

Es la que notificará las modificaciones, no sobre el conjunto de elementos, sino sobre los datos –Propiedades- de cualquier elemento de la colección. Las interfaces WPF/Silverlight basados en Data Bindings son los típicos clientes de esta interfaz y son los que representan la modificación de cualquier propiedad de cualquier elemento de una colección ObservableCollection<T> en el elemento enlazado de la interfaz.

Por ejemplo supongamos que tenemos la clase Empleado que pertenecerá a una ObservableCollection<T> y que posteriormente será enlazada a la interfaz de una aplicación WPF. En primer lugar debemos implementar la interfaz INotifyPropertyChanged para proveer de un mecanismo de notificación sobre las propiedades de la clase. Así, si la clase Empleado tiene dos propiedades llamadas Login y Nombre en ambos setters de la propiedad deberíamos ejecutar el evento PropertyChanged() tal y como se muestra a continuación:

public class Empleado : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        
        private string _login;
        private string _nombre;
        
        public string Login
        {
            get { return _login; }
            set
            {
                _login = value;
                PropertyChanged(this, 
                    new PropertyChangedEventArgs("Login"));
            }
        }
 
        public string Nombre
        {
            get { return _nombre; }
            set
            {
                _nombre = value;
                PropertyChanged(this, 
                    new PropertyChangedEventArgs("Nombre"));
            }
        }
    }

A partir de aquí, la clase Empleado debe residir dentro de una colección ObservableCollection<Empleado> y ser enlazada a un elemento cualquier, por ejemplo un datagrid. Una ejemplo trivial con una única grid y un boton que agregaría un nuevo empleado a la colección seria:

public partial class MainWindow : Window
{
    private readonly ObservableCollection<Empleado> users 
        = new ObservableCollection<Empleado>();
 
    public MainWindow()
    {
        InitializeComponent();
            
        datagrid1.DataContext = users;
    }
 
    private void button1_Click(object sender, RoutedEventArgs e)
    {
        users.Add(new Empleado()
        {
            Login = "jmtorres",
            Nombre = "José Miguel"
        });
    }
}

En el XAML únicamente deberiamos hacer uso de los Data Bindings de WPF:

<Grid>
    <DataGrid Name="dataGrid1" ItemsSource="{Binding}" AutoGenerateColumns="False">
        <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding Login}" Header="Login" />
            <DataGridTextColumn Binding="{Binding Nombre}" Header="Nombre" />
        </DataGrid.Columns>
    </DataGrid>
    <Canvas>
        <Button Click="button1_Click" ></Button>
    </Canvas>
</Grid>

A continuación detallo enlaces que tratan de forma más específica los Data Bindings tanto en WPF como en Silverlight utilizando colecciones ObservableCollection<T>:

 

System.Collections.ObjectModel.ReadOnlyCollection<T>

ReadOnlyCollection<T> es la versión Solo Lectura de la colección Collection<T>. Está especialmente para ser extendida en lugar de crear colecciones personalizadas desde zero y su peculiaridad, como su propio nombre indica es que carece de los 4 métodos que en la clase Collection<T> estaban declarados como virtuales y que se detallan a continuación:

protected virtual void ClearItems();
protected virtual void InsertItem(int index, T item);
protected virtual void RemoveItem(int index);
protected virtual void SetItem(int index, T item);

Por ultimo se detalla una relación de clases de .NET Framework que extienden las funcionalidades de ReadOnlyCollection<T>

System.Object
  System.Collections.ObjectModel.ReadOnlyCollection<T>

    System.Collections.ObjectModel.ReadOnlyObservableCollection<T>
    System.Data.Metadata.Edm.ReadOnlyMetadataCollection<T>
    System.Security.Cryptography.ManifestSignatureInformationCollection
    System.ServiceModel.Channels.AddressHeaderCollection
    System.Windows.Input.StylusButtonCollection
    System.Windows.Input.StylusDeviceCollection

System.Collections.ObjectModel.ReadOnlyObservableCollection<T>

La descripción oficial que hace el MSDN Library acerca de esta clase es que: “ReadOnlyObservableCollection es un wrapper –una envoltura- de sólo lectura sobre una colección ObservableCollection”. La percepción que tengo yo al respecto, siempre desde el respeto y la ignorancia especialmente sobre esta clase, es que no tengo ni pajolera idea de cual es su utilidad real llegando incluso a dudar de que realmente la tenga, con lo que no indagaré más al respecto.

-Colecciones Genericas- Coleccionando objetos en .NET Framework (II)

Introducción

Esta serie de artículos pretende mostrar las características y peculiaridades de las colecciones en .NET. El objetivo no es mostrar las situaciones en las que cada una de los diferentes tipos de colecciones pueden utilizarse en cada contexto sino la de conocer las mismas, ventajas y desventajas, para poder seleccionar el tipo de colección más apropiado en cada momento.

La serie cubre (entre corchetes el estado):

  • Colecciones No Genericas
  • Colecciones Genéricas System.Collections.Generic (este post)
  • Colecciones de System.Collections.ObjectModel (en desarrollo)
  • Colecciones nuevas en CLR 4.0 (no es definitivo además solo hay una)
  • Cota superior asintótica de las colecciones del CLI. aka Notación de Landau - O Grande- (en desarrollo)
  • Power Collections y C5 (por ahí andan)
  • Rx  (si hay ganas y tiempo)

Colecciones Genéricas

Sin lugar a dudas, uno de los conceptos que más provecho ha sacado de la genericidad han sido las colecciones. Practicamente todas las colecciones utilizadas hasta entonces tienen su equivalente dentro del espacio de nombre System.Collections.Generic además de la aparición de nuevas colecciones fruto de la flexibilidad que otorga los tipos generéricos.

En la siguiente tabla podemos ver algunas de estas colecciones (Fuente: Blog de Krzysztof Cwalina )

No Genericas                       Similares de tipo Generico
ArrayList                               List<T>
Hashtable                              Dictionary<TKey,TValue>
SortedList                             SortedList<TKey,TValue>
Queue                                   Queue<T>
Stack                                    Stack<T>
IEnumerable                          IEnumerable<T>
ICollection                            N/A (use IEnumerable<T> anything that extends it)
N/A                                      ICollection<T>
IList                                      IList<T>
CollectionBase                      Collection<T>
ReadOnlyCollectionBase      ReadOnlyCollection<T>
DictionaryBase                     N/A (just implement IDictionary<TKey,TValue>
N/A                                      SortedDictionary<TKey,TValue>
N/A                                      KeyedCollection<TKey,TItem>
N/A                                      LinkedList<T>

NOTA: No todas las colecciones genéricas se encuentran en el espacio de nombres System.Collections.Generic. Algunas las veremos en el siguiente post bajo el espacio de nombre System.Collections.ObjectModel.

De la misma forma que en la colecciones no genéricas, me gustaria empezar desgranando el núcleo de toda colección: el iterador/enumerador.

El Enumerador genérico

Como es de preveer existe una interfaz IEnumerator<T> dentro del espacio de nombres System.Collections.Generic cuya firma es:

public interface IEnumerator<out T> : IDisposable, IEnumerator
{
    new T Current { get; }
}

Por consiguiente, la interfaz IEnumerable<T> también tiene su equivalente genérico y se describe como:

public interface IEnumerable<out T> : IEnumerable
{
    new IEnumerator<T> GetEnumerator();
}

NOTA: La importancia y funcionamiento de ambas se describe en el post anterior.

En dichas firmas ya empezamos a ver las primeras pecualiridades y es que en ambos casos cada una de las interfaces implementa su equivalente no genérico para mantener la compatibilidad hacía las colecciones no genéricas. Por otro lado IEnumerator<T> implementa IDisposable. La razón nos la explica el propio Krzysztof Cwalina aqui y no es más que para contemplar determinados escenarios dónde la colección que implementa IEnumerator<T> pueda destruir recursos “externos” utilizados tales como conexiones en base de datos para la lectura de filas o manejadores de archivos para la iteración de ficheros. Por último ambas interfaces son covariantes a T en el CLR 4.0.

Uno de los cambios más importantes es la abstracción de ICollection<T>. Si nos fijamos en la tabla de equivalencias del inicio de este post veremos que ICollection no tiene ninguna equivalencia en la parte genérica de la mismo forma que ICollection<T> tampoco la tiene en la parte no genérica. Fijémonos en su firma:

ICollection<T>

public interface ICollection<T> : IEnumerable<T>, IEnumerable
{
    int Count { get; }
    bool IsReadOnly { get; }
    void Add(T item);
    void Clear();
    bool Contains(T item);
    void CopyTo(T[] array, int arrayIndex);
    bool Remove(T item);
}

Las unicas propiedades que tienen en común son CopyTo y Count. El método SyncRoot y la propiedad IsSynchronized se han eliminado y se han añadido los métodos Add, Contains, Clear y Remove. Queda evidente pues que lo único que comarten es el nombre ya que la abstracción es bien distinta.

NOTA: Krzysztof Cwalina lo argumenta diciendo que en realidad ICollection no tenia mucho sentido. .NET Framework no tenia ningún tipo de colección que representara una colección indexada de lectura y escritura; de ahí surge ICollection<T>.

En cuanto a las equivalencias de IList e IDictionary:

IList<T>

public interface IList<T> : ICollection<T>, IEnumerable<T>, IEnumerable
{
    T this[int index] { get; set; }
    int IndexOf(T item);
    void Insert(int index, T item);
    void RemoveAt(int index);
}

IDictionary<TKey,TValue>

public interface IDictionary<TKey, TValue> : ICollection<KeyValuePair<TKey, TValue>>,
                                             IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable
{
    TValue this[TKey key] { get; set; }
    ICollection<TKey> Keys { get; }
    ICollection<TValue> Values { get; }
    bool ContainsKey(TKey key);
    void Add(TKey key, TValue value);
    bool Remove(TKey key);
    bool TryGetValue(TKey key, out TValue value);
}

Podriamos afirmar, pues que ambas tienen su correspondencia en el espacio de nombre System.Collections.Generic pese a que IDictionary tiene algunas pecualiridades debido a la flexibilidad de los genéricos y que veremos más tarde. Por último siguen implementando la interfaz no genérica IEnumerable para mantener la compatibilidad con colecciones no genéricas.

Ahora veremos los diferentes tipos de colecciones en base a la interfaz que utilizan.

Colecciones Genéricas

Colecciones regulares (System.Collections.ICollection)

NOTA: Pese a que MSDN Library afirma que tanto Queue<T> y Stack<T> hacen uso de ICollection<T> esto no es cierto. Implementan ICollection.

Este tipo de colecciones también son conocidas como colecciones ordenadas o simplemente collecciones –me he permitido la libertad de denominarlas estándar o regulares para diferenciarlas de las específicas-. Hago hincapié en ello pues encontré varias formas de denomiarlas. De hecho, más allá de la colección Collection que como vimos anteriormente es abstracta y no es más que una evolución de CollectionBase utilizada en las versiones tempranas del CLR, existe un par de clases que podriamos catalogar dentro de este grupo y que vienen representadas por las clases Stack<T> y Queue<T>.

NOTA: Ambas guardan una estrecha relación ya que en ambos casos los elementos se almacenan según el orden de llegada. Nótese que el término “ordenación” utilizado anteriormente no es una ordenación lógica sobre una propiedad del conjunto de elemento; este tipo de elementos los veremos más adelante y podrían estar catalogados como colecciones especializadas.

La diferencia principal entre Stack<T> y Queue<T> reside en el orden en el que los elementos son obtenidos. En ambos casos almacenan elementos en estricto orden de llegada y mientras que en la clase Stack<T> responde a LIFO (Last Input First Output) en el caso de Queue<T> responde a FIFO (First Input First Output). Ambas clases derivan de ICollection e IClonable y cada una de ellas utiliza un método distinto para añadir y quitar un elemento de la colección. Push y Pull para Stack y Enqueue y Dequeu para Queue.

var queue = new Queue<string>();
var stack = new Stack<string>();
 
queue.Enqueue("A");
queue.Enqueue("B");
queue.Enqueue("C");
queue.Enqueue("D");
 
stack.Push("A");
stack.Push("B");
stack.Push("C");
stack.Push("D");
 
Console.WriteLine("Dequeue-ing...");
foreach (var elemento in queue)
    Console.WriteLine(elemento);
 
Console.WriteLine("Pop-ing...");
foreach (var elemento in stack)
    Console.WriteLine(elemento);

Colecciones (System.Collections.Generic.ICollection<T>)

LinkedList<T> es una colección de nodos enlazados que implementa, entre otros ICollection<T>. El nucleo central de LinkedList<T> es System.Collections.Generic.LinkedListNode<T> la cual es una clase cuya caracteristica fundamental es que almacena el nodo immediatamente posterior y anterior y portanto todos y cada uno de los nodos mantienen una referencia de orden. Más info: Wikipedia.

A partir de aquí el funcionamiento es relativamente sencillo. Lo que iremos almacenando son objetos del tipo LinkedListNode<T> de tipo T en una colección LinkedList<T>. Las ventajas que nos ofrece este tipo de listas que podemos insertar immediantamente antes o despues de un determinado nodo practicamente con un coste O(1)  a través de los métodos AddBefore() y AddAfter(). Además podremos añadir un elemento al inicio o al final de la lista enlazada mediante AddFirst() y AddLast() respectivamente.

LinkedList<T> mantiene siempre tanto el primer como el último nodo a través de las propiedades First y Last siempre y cuando el objecto LinkedList<T> tenga más de 0 elementos (linkedList.Count => 1).  En el siguiente ejemplo, aunque trivial, muestra alguna de las posibilidades de LinkedList<T>.

var linkedList = new LinkedList<string>();
 
//añadimos el que va a ser el primer elemento 
linkedList.AddFirst("Alfa");
 
//mantenemos una instanacia al ultimo 
//elemento insertado mediante linkedListNode
//NOTA: tambien podriamos utilizar linkedList.AddLast...
var linkedListNode = linkedList.AddAfter(linkedList.First, "Beta");
linkedListNode = linkedList.AddAfter(linkedListNode, "Eco");
linkedListNode = linkedList.AddAfter(linkedListNode, "November");
            
//como por ejemplo aqui
linkedList.AddLast("Romeo");
linkedList.AddLast("Zulu");
 
//insertamos despues de "Eco"
linkedListNode = linkedList.Find("Eco");
if (linkedListNode != null) 
    linkedList.AddBefore(linkedListNode, "Delta");
 
foreach(var elemento in linkedList)
    Console.WriteLine(elemento);
 
//resultados...
//Alfa
//Beta
//Eco
//November
//Romeo
//Zulu

Colecciones específicas

Otro tipo de agrupamiento para las colecciones específicas (es decir, las que se extienden más allá de ICollection) es de colecciones de acceso por clave o por índice. A continuación veremos el conjunto de colecciones agrupadas por clave (a través de IDictionary<TKey, TValue>) y posteriormente las que son agrupadas por índice (a través de IList<T>) y por último aquellas colecciones que hacen uso tanto de las características de índice y de clave.

Derivadas de System.Collections.Generics.IList<T>

En el ejemplo con el que abríamos el primer post vimos un ejemplo con System.Array, un claro ejemplo de colección basado en índices, también conocido en inglés como zero-based indexed collection. System.ArrayList es otro claro ejemplo de colección indexada que surge de la necesidad de poder redimensionar el tamaño de una colección de forma dinámica, limitación encontrada en System.Array. De hecho, ArrayList podría ser descrita como un híbrido entre una colección y una matriz de elementos ya que los elemento siguen almacenándose en orden de llegada pese a que pueden ser obtenidos mediante el índice relativo de la propia colección.

System.Collections.Generics.List<T> es equivalente natural a ArrayList en la parte de genericos. Es en esencial un ArrayList mejorada en rendimiento, tamaño y velocidad. Es quizás la colección más utilizada y más adecuada a la gran mayoria de escenarios debido a su flexibilidad y características.

En cuanto a la capacidad, de la misma forma que en ArrayList, podemos indicársela en el constructor o bien no hacerlo y la propia colección irá redimensionándose. Debido al coste que tiene la operación de redimensionamiento, List<T> crece en bloques del doble de su capacidad, siendo 4 su capacidad inicial, si no se indica el tamaño por defecto. Esto significa que tras la instanciación de:

var list = new List<double> { 20.0d };
//list.Capacity = 4
//list.Count = 1

El objeto list poseerá una capacidad de 4 elementos, tres de ellos null. Tras ir añadiendo más elementos list siempre irá creciendo en orden de 4, 8, 16, 32, 64, … elementos dejando los no utilizados con el valor por defecto de cada tipo, esto es default(T), o más concretamente null para los tipos por referencia y 0 para los tipos por valor. Indentificaremos la capacidad total mediante la propiedad Capacity, siempre multiples de 4, y la cantidad de elementos no null/0 mediante Count.

Podemos exigir que un objeto List<T> tenga un tamaño fijo predefinido. Sin embargo, es muy común confundir esta limitación o característica con la cantidad de elementos que se le puede pasar por parámetro en el constructor de la clase List<T>. Otro error común es indicar una capacidad elevada en previsión de crecimiento. Si es cierto que esto es una buena practica si el numero de elementos a añadir es finalmente inferior a la capacidad inicial, no lo es si el numero de elementos final es superior puesto que el crecimiento de la ArrayList será multiple a la capacidad inicial. Es decir, por ejemplo, el siguiente ejemplo crea un List<T> con un tamaño predefinido de 100 elementos. Por un lado podemos ver como el objeto arrayList acepta 1000 elemento (10 veces más de lo inicialmente previsto) sin ningún problema. Sin embargo, tras el bucle podemos observar que la capcidad –Capacity- (no cantidad –Count- de elementos) es de 1600 y es debido a que el crecimiento ha sido de 100, 200, 400, 800 y 1600. O sea que tenemos un List<T> de 1600 elementos de capacidad y realmente se estan utilizando 1000.

var list = new List<string>(100);
 
for (int i = 0; i <= 1000; i++)
    list.Add(i.ToString());
//list.Capacity = 1600
//list.Count = 1000

Si hacemos la misma interación sin un tamaño predefinido, la capacidad final será de 1024.

var list = new List<string>();
 
for (int i = 0; i <= 1000; i++)
    list.Add(i.ToString());
//list.Capacity = 1024
//list.Count = 1000

Derivadas de System.Collections.Generics.IDictionary<T>

La diferencia fundamental entre SortedList<TKey,TValue> y List<T> es que mientras en List<T> se almacenan los elemento por orden de “llegada” en SortedList<TKey,TValue> se almacena una pareja valor/clave y tanto se puede acceder por clave como por índice.

Internamente, SortedList<TKey,TValue> mantiene dos objetos IList<T> internos, uno para el almacenamiento de claves y otro para el almacenamiento de valores la cuales se acceden mediante un objeto de la clase KeyValuePair<TKey,TValue>. Como su propio nombre indica, SortedList<TKey,TValue> mantiene el conjunto de elementos ordenados por clave. La clave puede ordenarse en función a una implementación específica de IComparer<T> o bien mediante la interfaz IComparable<T> que los propios tipos de las claves – de sus elementos - indican. En el siguiente ejemplo añadimos 4 elementos de tipo string y observamos el resultado. Fijémonos como el IComparer<T> por defecto es CaseSensitive es decir System.Collections.Generic.Comparer<T>.Default (ya que está utilizando la implementación IComparable<T> derivado de la clase String).

var sortedList = new SortedList<string,string>()
                                 {
                                     {"Z", "Z"},
                                     {"A", "A"},
                                     {"a", "a"},
                                     {"B", "B"}
                                 };
 
foreach (var elemento in sortedList)
    Console.WriteLine(elemento.Value);
 
//Resultado:
//a
//A
//B
//Z

Sin embarago, si utilizáramos un IComparer<T> propio y especificaramos explicitamente que la comparación sea Case Insensitive, obtendriamos un error ya que no es posible añadir dos elemento con la misma clave al tratar de la misma forma o valor las cadenas “a” y “A”:

public class CaseInsensitiveComparerSample<T> : IComparer<T>
{
    public int Compare(T x, T y)
    {
        return ((new CaseInsensitiveComparer())
            .Compare(y, x));
 
    }
}
 
//implementación
var sortedList = new SortedList<string,string>(
                new CaseInsensitiveComparerSample<string>()
                )
                                 {
                                     {"Z", "Z"},
                                     {"A", "A"},
                                     // Argument Exception
                                     {"a", "a"},// Item has already been added. 
                                     // Key in dictionary: 'A'  Key being added: 'a'
                                     {"B", "B"}
                                 };

Dictionary<TKey,TValue>

Dictionary<TKey, TValue> es un HashTable fuertemente tipado. La diferencia entre ambos se encuentra en como gestiona las colisiones de los codigos hash de sus elementos en el algoritmo hash. Mientras que HasTable realiza un sondeo cuando existe una colision reubicando el elemento en el siguiente cubo –bucket- libre mientras que Dictionary<TKey, TValue> realiza un encadenamiento de los elementos con un mismo codigo hash almacenándolos en una lista asociada a un mismo cubo –bucket-. Para obtener más información al respecto podeis consultar el post System.Collections.Generic Dictionary Capacity, Hashing, and Collisions.

Por lo demás y como comentamos antes el funcionamiento es en esencial el de un HashTable. Todos los elementos implementan de forma explícita o implícita un código Hash, a través, por ejemplo, de la clase base System.Object. Como peculiaridad, Dictionary<TKey,TValue> utiliza la también estructura KeyValuePair<TKey,TValue> en lugar de la estructura DictionaryEntry que utiliza HasTable. Un ejemplo sencillo seria:

var dictionary = new Dictionary<int,string>
                                {
                                    {616000, "Juan M."},
                                    {616100, "Rafael H."},
                                    {616200, "Joaquin A."},
                                    {616210, "Alberto P."}
                                };
 
foreach (KeyValuePair<int,string> elemento in dictionary)
{
    Console.WriteLine(
        string.Format("Key: {0} Value:{1}",
                        elemento.Key, elemento.Value));
}

SortedDictionary<TKey,TValue>

La colección que mezcla las capacidades del Dictonary<TKey, TValue> con un conjunto de claves ordenado como hacía SortedList<T> es SortedDictionary<TKey, TValue>. Aqui es dónde reside la mayoría de las preguntas que nos hacemos acerca de cuál tipo de colección utilizar.

Según información del MSDN Library, establece que:

Where the two classes differ is in memory use and speed of insertion and removal:

Veamos las diferencias reales de los dos primeros puntos: memoria y rendimiento.

Memoria

Para tratar de hacer una comparativa del tamaño de memoria utilizado entre uno y otro vamos a ejecutar un código que lo único que hará es añadir 1.000.000 de elementos string de clave int.

NOTA: La inserción se hace de forma secuencias con lo que el coste en la operación de agregación será mucho menor en SortedList. Esto es una excepción puesto que por norma general el valor de la clave será desordenada y es en ese punto, cuando hablemos del rendimiento lo veremos, dónde SortedDictionary es mucho más rápido.

Lo realmente importante del siguiente código es el espacio en memoria que se utiliza para la manipulación de los dos objectos SortedList y SortedDictionary:

var sortedList =
    new SortedList<int, string>();
var sortedDictionary =
    new SortedDictionary<int, string>();
 
int items = 1000000;
 
for (int i = 0; i < items; i++)
        sortedList.Add(i,i.ToString());
 
for (int i = 0; i < items; i++)
    sortedDictionary.Add(i,i.ToString());

Tras la ejecución con CLRProfiler vemos el grafo de asignación de bytes en memoria de:

la SortedList:

image

y la representacción de SortedDictionary:

image

Como podemos comprobar el espacio asignado en memoria es superior en el caso de SortedDictionary.

Como curiosidad podemos apreciar como cada uno de los objetos trata de forma bien distinta la información en memoria. SortedList al final acaba generando dos Arrays, una de claves y otra de valores del tipo System.Int32[] y System.String[] respectivamente. Por otro lado, SortedDictionary hace uso de un tipo utilizado internamente llamado Generic.TreeSet. Este tipo es un arbol binario utilizado, como dije antes, de forma interna para la manipulación de objetos del tipo Dictionary. La razón por la cual no está expuesta como API pública es debido a que el enfoque de este mismo tipo seria muy diferente. Básicamente Microsoft decidió utilizar únicamente de forma interna y no exponerla como API pública. Además de Generic.TreeSet podemos ver un objeto System.String que es dónde almacena el valor del objeto SortedDictionary.

internal class TreeSet<T> : ICollection<T>, IEnumerable<T>, ICollection, 
    IEnumerable, ISerializable, IDeserializationCallback 
Rendimiento

Para trata de evaluar el rendimiento entre ambas colecciones vamos a realizar una prueba muy similar, pero no vamos a dar ventaja a SortedList añadiendo elementos ordenados y es por ello que vamos a substituir las claves del tipo int al tipo System.Guid generándose uno diferente cada vez de forma que SortedList tenga que ordenar la clave tras cada inserción.

El código podria ser algo tal que así:

var sortedList =
    new SortedList<Guid, string>();
var sortedDictionary =
    new SortedDictionary<Guid, string>();
 
int items = 100000;
 
for (int i = 0; i < items; i++)
        sortedList.Add(Guid.NewGuid(), i.ToString());
 
for (int i = 0; i < items; i++)
    sortedDictionary.Add(Guid.NewGuid(), i.ToString());

El resultado del Performance Profiling del VS 2010 es tal y como muestra la siguiente captura de pantalla.

image

La operación SortedList.Add ocupa más del 97% del tiempo total de ejecución del código mientras que SortedDictionary.Add apenas llega al 2% por lo tanto queda demostrado el rendimiento entre ambas clases en operaciones de inserción y eliminación.

Conclusión

Además de las nombradas en este post existen otras menos utilizadas dentro del espacio de nombre de colecciones genéricas.

Otras referencias

http://en.how-to.mobi/index.php?sd=es&id=221691

 http://blogs.msdn.com/b/kcwalina/archive/2004/08/06/210297.aspx

-Colecciones No Genericas- Coleccionando objetos en .NET Framework (I)

Introducción

Esta serie de artículos pretende mostrar las características y peculiaridades de las colecciones en .NET. El objetivo no es mostrar las situaciones en las que cada una de los diferentes tipos de colecciones pueden utilizarse en cada contexto sino la de conocer las mismas, ventajas y desventajas, para poder seleccionar el tipo de colección más apropiado en cada momento.

La serie cubre (entre corchetes el estado):

  • Colecciones No Genericas (actual post)
  • Colecciones Genéricas de System.Collections.Generic (en desarrollo)
  • Colecciones de System.Collections.ObjectModel (en mi cabeza)
  • Colecciones nuevas en CLR 4.0 (no es definitivo además solo hay una)
  • Cota superior asintótica de las colecciones del CLI. aka Notación de Landau - O Grande- (en desarrollo)
  • Power Collections y C5 (por ahí andan)
  • Rx  (si hay ganas y tiempo)

¿Que es una colección?

Se entiende como colección un conjunto de entidades lógicamente relacionadas –es decir que deberían tener algo en común-. Así una colección de objetos de tipo string podría ser declarada como un System.Array de la siguiente forma en C#. 

var cadenas = new string[]
                     {
                        "A", "B"
                     };

Sin embargo, esta declaración tiene algunos matices como por ejemplo que en muy pocas ocasiones conocemos el tamaño fijo que tendrá y por lo tanto se convierte en una limitación del propio System.Array, por ejemplo. Básicamente, las características y comportamiento del tipo de colección a utilizar nos ayudará o limitará en mayor o menor medida.

Por lo tanto, primero de todo me gustaría empezar definiendo que es para .NET Framework una colección. Desde el punto de vista de .NET Framework, una colección es cualquier tipo que implemente System.Collections.ICollection, System.Collections.IDictionary o System.Collections.IList, sin embargo no siempre tenemos claro que otorga especialemente cada una de estas interfaces. Vayamos por partes.

El Enumerador

Si empezaramos a desgranar todos los tipos de colecciones disponibles en el CLR encontraríamos un denominador común “oculto”, la interfaz IEnumerator. Si para que una colección sea considerada como tal en .NET Fx debe implementar una de las 3 interfazes expuestas anteriormente, todas estas interfaces deben implementar IEnumerable la cual no hace más exponer un IEnumerator.

Podríamos empezar mostrando la firma tanto de ICollection:

[ComVisible(true)]
public interface ICollection : IEnumerable
{
    int Count { get; }
    object SyncRoot { get; }
    bool IsSynchronized { get; }
    void CopyTo(Array array, int index);
}

como de IDictionary

[ComVisible(true)]
public interface IDictionary : ICollection, IEnumerable
{
    object this[object key] { get; set; }
    ICollection Keys { get; }
    ICollection Values { get; }
    bool IsReadOnly { get; }
    bool IsFixedSize { get; }
    bool Contains(object key);
    void Add(object key, object value);
    void Clear();
    new IDictionaryEnumerator GetEnumerator();
    void Remove(object key);
}

como de IList.

[ComVisible(true)]
public interface IList : ICollection, IEnumerable
{
    object this[int index] { get; set; }
    bool IsReadOnly { get; }
    bool IsFixedSize { get; }
    int Add(object value);
    bool Contains(object value);
    void Clear();
    int IndexOf(object value);
    void Insert(int index, object value);
    void Remove(object value);
    void RemoveAt(int index);
}

Y para empezar nos encontramos con otra característica que seguro muchos no habíamos visto anteriormente y es que tanto IDictionary com IList implementan, a su vez ICollection.

Es aquí, en este punto, dónde empieza a avistarse la diferencia entre las tres interfaces y podemos catalogarlas en dos conjuntos: Colecciones estándar o regulares y Colecciones específicas. Es obvio que tras ver la firma de cada una de ellas podemos afirmar que IList y IDictionary son colecciones específicas (ambas extienden ICollection) e ICollection es una colección estándard o regular.

NOTA: Utilizo el térmio “específicas” no especializadas –Specialized- cuyas colecciones estan en el espacio System.Collections.Specialized y que veremos más tarde.

Primera pregunta que surge, ¿Conociendo que System.Collection.List es el principal “consumidor” de IList y que Collection hace lo mismo de ICollection, cuál de ellas deberíamos utilizar? La respuesta es relativamente sencilla. Collection, a diferencia de List es una clase abstracta y por tanto debe ser implementada para ser extendida. Esto nos da una pista que la solución reside en que Collection debe ser utilizada para ser expuesta a través de un API pública mientras que List implementa métodos de búsqueda y ordenación específicas listas para usar.

Volviendo al núcleo central del tema, es decir a IEnumerator, observamos que las tres interfaces además implementan IEnumerable con lo que es buen momento par aver la firma de la misma:

public interface IEnumerable
{
    IEnumerator GetEnumerator();
}

Tal y como se puede observar, y se ha comentado anteriormente, IEnumerable no hace más que retornar un IEnumerator. Es importante conocer y entender la figura de un enumerador/iterador pues es el que va a permitir la iteración sobre cada uno de los elementos de una colección. La sentencia foreach, por ejemplo, hace uso de él. IEnumerator únicamente permite la iteración, nunca la modificación del elemento. De hecho, si observamos su firma:

public interface IEnumerator
{
    object Current { get; }
    bool MoveNext();
    void Reset();
}
Podemos ver que, exluyendo Reset, tanto Current como MoveNext son métodos de navegación o iteración entre collecciones. El mecanismo es sencillo; Current indica un valor indefinido y por tanto se lanza una llamada a MoveNext. Si esta retorna True, Current contiene el primer elemento de la colección y así lo hará mientras el valor de MoveNext vaya siendo True. En el momento que éste sea False, Current indicará al último elemento de la colección.

NOTA: El método Reset se mantiene únicamente por compatibilidad COM con lo que queda fuera del alcance de este artículo.

Colecciones No Genéricas

Colecciones regulares (System.Collections.ICollection)

Este tipo de colecciones también son conocidas como colecciones ordenadas(*) o simplemente collecciones –me he permitido la libertad de denominarlas estándar o regulares para diferenciarlas de las específicas-. Hago hincapié en ello pues encontré varias formas de denomiarlas. De hecho, más allá de la colección Collection que como vimos anteriormente es abstracta y no es más que una evolución de CollectionBase utilizada en las versiones tempranas del CLR, existe un par de clases que podriamos catalogar dentro de este grupo y que vienen representadas por las clases Stack y Queue.

NOTA: (*) Ambas guardan una estrecha relación ya que en ambos casos los elementos se almacenan según el orden de llegada. Nótese que el término “ordenacióin” utilizado anteriormente no es una ordenación lógica sobre una propiedad del conjunto de elemento; este tipo de elementos los veremos más adelante y podrían estar catalogados como colecciones especializadas.

La diferencia principal entre Stack y Queue reside en el orden en el que los elementos son obtenidos. En ambos casos almacenan elementos en estricto orden de llegada y mientras que en la clase Stack responde a LIFO (Last Input First Output) en el caso de la cola responde a FIFO (First Input First Output). Ambas clases derivan de ICollection e IClonable y cada una de ellas utiliza un método distinto para añadir y quitar un elemento de la colección. Push y Pull para Stack y Enqueue y Dequeu para Queue.

var queue = new Queue();
var stack = new Stack();
 
queue.Enqueue("A");
queue.Enqueue("B");
queue.Enqueue("C");
queue.Enqueue("D");
 
stack.Push("A");
stack.Push("B");
stack.Push("C");
stack.Push("D");
 
Console.WriteLine("Dequeue-ing...");
foreach (var elemento in queue)
    Console.WriteLine(elemento.ToString());
 
Console.WriteLine("Pop-ing...");
foreach (var elemento in stack)
    Console.WriteLine(elemento.ToString());
 
//Resultado:
// Dequeue-ing...
// A
// B
// C
// D
// Pop-ing...
// D
// C
// B
// A

Son colecciones principalmente utilizadas, como es obvio, en contextos dónde el orden de llegada es altamente importante. A partir de aquí, la forma en la que se obtienen los elementos de la colección es la clave para decidir seleccionar una u otra clase.

Colecciones específicas

Otro tipo de agrupamiento para las colecciones específicas (es decir, las que se extienden más allá de ICollection) es de colecciones de acceso por clave o por índice. A continuación veremos el conjunto de colecciones agrupadas por clave (a través de IDictionary) y posteriormente las que son agrupadas por índice (a través de IList) y por último aquellas colecciones que hacen uso tanto de las características de índice y de clave.

Derivadas de System.Collections.IList

En el ejemplo con el que abríamos este artículo vimos un ejemplo con System.Array, un claro ejemplo de colección basado en índices, también conocido en inglés como zero-based indexed collection. System.ArrayList es otro claro ejemplo de colección indexada que surge de la necesidad de poder redimensionar el tamaño de una colección de forma dinámica, limitación encontrada en System.Array. De hecho, podría ArrayList ser descrita como un híbrido entre una colección y una matriz de elementos ya que los elementos siguen almacenándose en orden de llegada pese a que pueden ser obtenidos mediante el índice relativo de la propia colección.

En cuanto a la capacidad, podemos indicársela en el constructor o bien no hacerlo y la propia colección irá redimensionándose. Debido al coste que tiene la operación de redimensionamiento, ArrayList crece en bloques del doble de su capacidad, siendo 4 su capacidad inicial, si no se indica el tamaño por defecto. Esto significa que tras la instanciación de:

var arrayList2 = new ArrayList {20.0d};

//arrayList2.Capacity = 4



//arrayList2.Count = 1



El objeto arrayList poseerá una capacidad de 4 elementos, tres de ellos null. Tras ir añadiendo más elementos arrayList siempre irá creciendo en orden de 4, 8, 16, 32, 64, … elementos dejando los no utilizados con null. Indentificaremos la capacidad total mediante la propiedad Capacity, siempre multiples de 4, y la cantidad de elementos no null mediante Count.

Podemos exigir que un objeto ArrayList tenga un tamaño fijo predefinido. Sin embargo, es muy común confundir esta limitación o característica con la cantidad de elementos que se le puede pasar por parámetro en el constructor de la clase ArrayList. Otro error común es indicar una capacidad elevada en previsión de crecimiento. Si es cierto que esto es una buena practica si el numero de elementos a añadir es finalmente inferior a la capacidad inicial, no lo es si el numero de elementos final es superior puesto que el crecimiento de la ArrayList será multiple a la capacidad inicial. Es decir, por ejemplo, el siguiente ejemplo crea un ArrayList con un tamaño predefinido de 100 elementos. Por un lado podemos ver como el objeto arrayList acepta 1000 elemento (10 veces más de lo inicialmente previsto) sin ningún problema. Sin embargo, tras el bucle podemos observar que la capcidad –Capacity- (no cantidad –Count- de elementos) es de 1600 y es debido a que el crecimiento ha sido de 100, 200, 400, 800 y 1600. O sea que tenemos un ArrayList de 1600 elementos de capacidad y realmente se estan utilizando 1000.

var arrayList = new ArrayList(100);

for (int i = 0; i < 1000; i++)



arrayList.Add(i);



//arrayList.Capacity = 1600



//arrayList.Count = 1000



Si hacemos la misma interación sin un tamaño predefinido –es decir con tamaño por defecto igual a 4-, la capacidad final será de 1024.

var arrayList = new ArrayList(1);

 



for (int i = 0; i < 1000; i++)



arrayList.Add(i);



//arrayList.Capacity = 1024



//arrayList.Count = 1000



Otro error común es confundir tamaño predefinido o inicial con tamaño fijo. Un ArraList de tamaño fijo jamás admitirá la agregación o eliminación de elementos, pero si la modificación.

var arrayList = new ArrayList { 20.0d };

var arrayList2 = ArrayList.FixedSize(arrayList);



arrayList2.Add(145.0d); //NotSupportedException



// arrayList2.IsFixedSize = true



Identificaremos las ArrayList de tamaño fijo mediante la propiedad IsFixedSize y como vemos en el ejemplo la forma de generarlas es a través de un objeto del tipo ArrayList o IList existente. Por otro lado, IsReadOnly es una propiedad de lectura y escritura con lo que podremos controlar la restricción o no de escritura sobre el conjunto de elementos.

NOTA: ArrayList esta cayendo en desuso (si no lo ha hecho ya) desde la aparición de las colecciones genéricas.

La colección StringCollection forma parte de las colecciones especializadas agrupadas en el espacio de nombres System.Collections.Specialized. StringCollection está especialmente optimizada para la manipulación de elementos del tipo string; es en esencia un ArraList tipado para aceptar únicamente cadenas de texto. StringCollection es ideal para la manipulación de relativamente poca cantidad de datos de tipo string que son frecuentemente actualizados.

Derivadas de System.Collections.IDictionary

De la misma forma que tratávamos ArrayList como “tipo primitivo” para la implementación de IList, haríamos lo mismo para el tipo SortedList con la interfaz IDictionary.La diferencia fundamental es que mientras en ArrayList se almacenan los elemento por orden de “llegada” en SortedList se almacena una pareja valor/clave y tanto se puede acceder por clave como por índice.

Internamente, SortedList mantiene dos arrays, uno para el almacenamiento de claves y otro para el almacenamiento de valores la cuales se acceden mediante un objeto de la estructura DictionaryEntry. Como su propio nombre indica, SortedList mantiene el conjunto de elementos ordenados por clave. La clave puede ordenarse en función a una implementación específica de IComparer o bien mediante la interfaz IComparable que los propios tipos de las claves – de sus elementos - indican. En el siguiente ejemplo añadimos 4 elementos de tipo string y observamos el resultado. Fijémonos como el IComparer por defecto es CaseSensitive ya que está utilizando la implementación IComparable derivado de la clase String.

 
var sortedList = new SortedList()
                     {
                         {"Z", "Z"},
                         {"A", "A"},
                         {"a", "a"},
                         {"B", "B"}
                     };
 
foreach (var elemento in sortedList)
    Console.WriteLine(((DictionaryEntry)elemento).Value);
 
//Resultado:
//a
//A
//B
//Z

Sin embarago, si utilizáramos un IComparer propio y especificaramos explicitamente que la comparación sea Case Insensitive, obtendriamos un error ya que no es posible añadir dos elemento con la misma clave al tratar de la misma forma o valor las cadenas “a” y “A”:

public class CaseInsensitiveComparerSample : IComparer
{
    public int Compare(Object x, Object y)
    {
        return ((new CaseInsensitiveComparer())
            .Compare(y, x));
    }
}
 
//implementación
var sortedList = new SortedList(
    new CaseInsensitiveComparerSample ())
                        {
                            {"Z", "Z"},
                            {"A", "A"},
                            // Argument Exception
                            {"a", "a"},// Item has already been added. 
                            // Key in dictionary: 'A'  Key being added: 'a'
                            {"B", "B"}
                        }; 

Otro tipo de colección basada en IDictionary es System.Collections.Hashtable. Hashtable implementa tanto ICollection como IDictionary y ha sido ampliamente utilizado como tipo de colección idónea para la gestión de grandes cantidades de elementos debido a su alto rendimiento. Exige que la clave de sus elementos aunque no el valor hash de cada uno de ellos. De hecho, la ordenación del conjunto de elemento vendrá dado por el valor hash. DictionaryEntry seguirá jugando el mismo papel que lo hacía con SortedList ya que en ambos casos se almacena un par clave/valor.

Hablando más específicamente cada objecto de la colección Hashtable obtiene el valor hash de la llamada al método GetHashCode() heredado de System.Object o bien una propia implementación a través de la interfaz IHashCodeProvider. Cuando un elemento es agregado éste se almacenará en un sector de almacenamiento o cubo –bucket en inglés- de forma que su posterior localización será mucho más óptima. No importa el valor real del objeto pues cada uno de ellos tendrá su propio codigo hash y de este modo se reduce considerablemente el número de comparaciones. Así, por ejemplo, Hasthable situará dos elementos de tipo string con valores “picnic” y “basket” en distintos cubos o búckets; sin embargo los dos elemento de tipo string con valores “stressed” y “desserts” probablemente tengan el mismo codigo hash y por tanto los situará en un mismo bucket o cubo.

Realmente, la funcionalidad de un Hashtable es muy similiar al que ofrecen otras colecciones derivadas de IDictionary pero la comprensión de cómo se gestiona internamente el almacenamiento a través de códigos hash nos permite entender por un lado porque Hashtable es la colección que mayor rendimiento otorga y por otro lado las problemáticas que pueden generar la coincidencia de códigos hash si el algoritmo utilizado no es óptimo.

Un típico ejemplo seria:

 
var hashtable = new Hashtable
                    {
                        {"616-000-000", "Juan M."},
                        {"616-000-100", "Rafael H."},
                        {"616-200-000", "Joaquin A."},
                        {"616-200-100", "Alberto P."}
                    };
 
foreach (DictionaryEntry elemento in hashtable)
{
    Console.WriteLine(
        string.Format("Key: {0} Value:{1}",
                        elemento.Key, elemento.Value));
}

NOTA: Hablaré más extensamente sobre el tema de los conflictos en colecciones Hashtable en el siguiente post cuando trate la colección Dictionary<TKey, TValue>

StringDictionary, por su parte, juega el mismo papel que lo hacía StringCollection, pero si éste último era ideal para relativamente poca cantidad de elementos y su acceso es por índice, StringDictionary, al implementar IDictionary es ideal para una mayor cantidad de elementos. En este caso, también, se trata de una colección de elementos tipados ya que únicamente se aceptan elementos de tipo String.

 

Conclusión

Unicamente he expuesto las colecciones más utilizadas relativas a las no genéricas que he creído conveniente por propia experiencia exponer. En el siguiente post hablaremos de las colecciones genéricas que presenta el BCL.

 

[OT] Hadi Hariri y cena aniversario de CatDotNet

Buenas!!

Comentaros que mañana martes a las 19h tendremos el placer de tener con nostros a Hadi Hariri en la charla mensual de CatDotNet. Además, seguidamente nos desplazaremos a Capellades para celebrar la cena aniversario de CatDotNet dónde nos encontramos anualmente todos la gente de comunidad de la zona de Cataluña. Si estais por la zona, no dudes, en contactarnos!!!

Lugar?: Sala Ig-Nova Tecnospai. Av. Barcelona núm. 105 (Igualada)

Hora?: 19h de la tarde

 


Ver mapa más grande

Us hi esperem!!!!

Publicado por José Miguel Torres | 4 comment(s)
Archivado en:

¡¡Microsoft SQL Server Compact no ha muerto!!

Después del impacto que ha tenido la presentación del nuevo modelo de desarrollo que traerá tras de sí la nueva apuesta de Microsoft para telefónos móviles con Windows Phone 7 Series, y después de que más de uno se haya enfundado el traje de negro y preparado ya los preparativos para el funeral de .NET Compact Framework he oído rumores de algunos desarrolladores que, ante la visible desinformación de Microsoft que rodea la aparición WP7S, han decidido incluir dentro del mismo funeral a Microsoft SQL Server Compact, y eso me duele ;-)

En primer lugar .NET Compact Framework NO VA A MORIR de la misma forma que no lo va a hacer Windows Mobile 6.5. Mientras WP7S se orienta hacía un claro público consumidor/productivo, WinMo 6.5, por su parte, se quedará dando cobertura al importante parque de aplicaciones empresariales/industriales. Microsoft no ha dicho oficialmente lo contrario por lo que cabe esperar tanto el soporte para WiMo 6.5 y .NET Compact Framework.

Microsoft SQL Server Compact 3.5 y Visual Studio .NET 2010

Con SQL Server Compact 3.1 Microsoft presentó una características importantísima a la menor de las ediciones de SQL Server al hacerla multiplataforma. Esto significa que desde entonces SQL Server Compact no se liga únicamente a entornos de desarrollo para dispositivos móviles sino para lo que se denomina , aplicaciones móviles desarrolladas con WPF o Windows Forms e incluso desde Silverlight.

Por lo tanto, y siguiendo la costumbre, Visual Studio 2010 .NET instala MS SQL Server Compact SP2 con las últimas caracterísitcas en mayoria relacionadas con MS Sync Framework

Por qué Microsoft SQL Server Compact no debe morir

  1. Porque SQL Server Compact en una –la única en Microsoft- base de datos in-process.
  2. Porque SQL Server Compact es especialmente útil en aplicaciones del tipo Smart Client debido a su alta integración en entornos de sincronización o lo que se denomina base de datos caché.
  3. Porque SQL Server Compact aporta una facilidad de despliegue que además es compatible con ClickOnce.
  4. Porque hay escenarios en los que SQL Server Express no es el SGBD adecuado. En otros escenario no lo es SQL Server Compact. SQL Server Express NO es un rival de Compact.
  5. Porque Microsoft esta adoptando SQL Server Compact como SGBD embebido.
  6. Y por último y aunque sea el más trivial y menos importante, pq el Bandolero se pasó más de un año profundizando en el producto y materializandolo en loque fue su primer libro.

 

Conlusión

En definitiva, SQL Server Compact 3.5 SP2 seguirá siendo una opción válida ante cualquier nuevo desarrollo brindando todas las características anteriormente numeradas y que la hacen realmente única.

[CatDotNet] Dices tu de nServiceBus…

Buenas!! Pues el próximo viernes 26 de febrero tendremos el placer de contar en Igualada con Sergio Bermudez quién nos presentará lo bueno y lo malo –si es que lo hay- de nServiceBus del amigo Udi Dahan, y cuyo pretexto utilizaremos para tomar, a posteriori, unos cacharros entre amigos y saber más sobre los ESB (ver foto).

Así que si estás por las cercanías, ¡¡te esperamos!!

CatDotNet_peque%c3%b1a

Publicado por José Miguel Torres | 5 comment(s)
Archivado en:

Virtualización de Servicios con Managed Services Engines

Desde mis primeras incursiones en el desarrollo de Servicios empresariales, básicamente desde la aparición de las primeras betas de WCF, ha habido un miedo escénico que me ha atormentado y es la programación déspota e incontrolada de servicios, servicios y más servicios, lo que deriva en la producción de 300 servicios, con 300 enlaces distintos (no más de 10 comunes), en 50 endpoints y cuyo valor operativo era equivalente a 50 servicios bien diseñados y gobernados.  No concebía una arquitectura sólida de servicios sin una “torre de control” o una “cabina de mando” desde dónde poder ver, gestionar y modificar nuestros servicios.

Más adelante tuve la oportunidad de trabajar en una arquitectura SOA desarrollada en J2EE, dirigida por un ESB de Oracle y gestionada con herramientas de gobernabilidad SOA, que manejaban más de un centenar de servicios (proxy y legacy) y dónde la publicación y consumo de dichos servicios se realizaban a través de estrictas normas protocolarias (seguridad, documentación,…).

Ahora vuelvo, de nuevo, a tener la misma necesidad, diseñar una infraestructura de servicios y cuando hablo de infraestructura hablo de ese tipo de herramientas fundamentales para el control de todos y cada uno de los servicios. Pero ahora (en realidad hace ya un tiempo que existe) me encontré con un software, bajo licencia  Microsoft Public License (Ms-PL) y código abierto, que adopta de forma práctica la idea de Virtualización de Servicios, llamado Managed Services Engine.

Virtualización de Servicios

La idea básica del patrón de Virtualización de Servicios es el de aislar la complejidad de los servicios expuestos del cliente que los consume ya que  tras cada servicio se alberga una gran cantidad de aspectos tales como las localizaciones de los endpoints, las configuraciones de los enlaces, la aplicación de políticas, etc. Además muchas de las adopciones SOA a la practica no ofrecen soluciones sobre versionado de servicios, aplicación de políticas de seguridad o cambios operativos sin necesidad volver a codificar el servicio así como el cumplimiento del SLA entre el proveedor –nosotros- y el cliente.

Aparece la idea de Servicio Intermediario que desacopla el cliente de la implementación del servicio. Como tal, podemos ofrece varios servicios virtuales de una misma implementación para, por ejemplo, utilizarlo en distintos escenarios. Es aquí dónde encontramos la clave de la virtualización, en el servicio intermediario, pues todas las llamadas se realizaran a través de este y podremos modificar su comportamiento sin comprometer los modelos del servicio.

 

Managed Services Engine

Microsoft Services SOA Infraestructure ofrece una solución de virtualización de servicios a través de Managed Services Engine (MSE). Como cabe esperar, MSE está basado en la plataforma Windows, esto es, Windows Server 2003/2008, SQL Server 2005/2008 y .NET Framework 3.5, especialmente con Windows Communication Foundation para la interceptación de comunicaciones entre servicios virtuales y reales.

MSE puede integrarse tanto con MS Biztalk Server 2006 R2 / 2009 para proporcionar capacidades adicionales tales como la monitorización de las actividades de negocio (BAM), el Business Rules Engine o el ESB Toolkit, entre otros. Además también podemos utilizar los servicios Azure a través de Azure AppFabric, especialmente con .NET Service Bus.

MSE consiste, básicamente, en tres componentes:

  • Messenger: proporciona la normalización del mensaje de entrada a través de los servicios virtuales. Este componente soporta además la aplicación de políticas (de transformación por ejemplo, tanto de peticiones como de respuestas) así como el mapeo de protocolos.
  • Broker: este componente obtiene el mensaje normalizado y lo reconvierte a la operación (es decir la implementación de un método del servicio) y su respectiva versión (pues podemos tener más de una operación con distintas versiones).
  • Dispatcher: una vez se tiene el mensaje y la operación pertinente, dispatcher invoca el método del servicio y se transmite dicho mensaje.

Recalcar que estos tres componentes están totalmente desacoplados unos de otros con lo que podríamos distribuirlos de forma que obtendríamos una gran cantidad de tipologías del sistema. Todo esto es gracias a la catalogo del servicio (Service Catalog), también conocido como repositorio de metadata o simplemente repository o repositorio, ya que contiene todos los modelos de los servicios que hospeda el runtime del MSE –incorpora asistentes para la importación de servicios a través del WSDL y otros mecanismos para servicios POX o REST-. Como dije anteriormente, MSE contiene una implementación de WCF así que es fácil intuir que la comunicación entre ellos se realizan a través de canales de mensajería. El repositorio, por último, utiliza una base de datos SQL Server y la información puede ser publicada en un registry externo UDDI 2.0/3.0.

Por último, MSE contiene una interfaz para la administración de los servicios –MSE Model Viewer- así como una herramienta de test –MSE Universal Service Tester-.

image

image

En próximos posts hablaré de las diferentes posibilidades que ofrece MSE desde el punto del vista del rol (developer, IT, architect,…) y como familiarizarse MSE.

[CatDotNet] Eduard Tomàs hablando sobre ASP.NET MVC en Igualada? Comorrr?

Pues sí, Eduard Tomàs, habitual y conocido de geeks.ms y de CatDotNet así como en presentaciones MSDN de Microsoft Ibérica , nos presenta este viernes en Igualada las bondades de ASP.NET MVC.

Si estáis por la zona no dudéis en asistir!!!

Lugar: Sala Ig-Nova Tecnospai. Av. Barcelona núm. 105 (Igualada) a las 19h.

 


Ver mapa más grande

Publicado por José Miguel Torres | 1 comment(s)
Archivado en:

Inicialización con System.Lazy<T> en .NET Framework 4.0

Una de las novedades de .NET Framework 4.0 es la presentación de la clase System.Lazy<T>. En programación, una inicialización Lazy (el término Lazy significa, literalmente, gandul o retardado) es un método de inicialización que permite que el objeto no se instancie hasta que se llame por primera vez, es decir hasta que sea utilizado. En el ciclo de vida de una aplicación, los métodos y propiedades de una clase que componen existen, es decir se instancian en memoria y permanecen ahí desde la creación  hasta que la destrucción de la clase.

Una clase Customer dónde el constructor carga una lista genérica de Order –inicializa un objecto List<Order> – éste permanece en memoria pese a que incluso es posible que ni siquiera lo necesitemos. Hasta .NET Framework 4.0 la implantación de este tipo de inicializaciones se realiza mediante programación retrasando la inicialización de un objeto hasta que realmente se necesitara; en el caso de la clase Customer, por ejemplo, instanciaríamos el objeto List<Order> en un método LoadOrders() o GetOrders(), por ejemplo. En el caso de multithreading, la cosa se complica aún más y a veces el planteamiento o diseño de la clase no es suficiente.

Como novedad esta característica ya forma parte en .NET Framework 4.0 a través de System.Lazy<T> y aporta soporte Thread-Safety y una política de propagación de excepciones consistente para dar soporte al multithreading. 

A partir de ahora nos olvidaremos de las técnicas anteriores y utilizaremos System.Lazy<T> para inicializaciones perezosas. Veamos un ejemplo:

   1: static void Main(string[] args)
   2: {
   3:     Lazy<string> cadena = new Lazy<string>(delegate
   4:                                                 {
   5:                                                     return "Ejemplo Lazy";
   6:                                                 });
   7:  
   8:     Console.WriteLine(string.Format("isValueCreated: {0}", cadena.IsValueCreated));
   9:     //podemos ejecutar cualquier acción y no se ejecutará hasta...
  10:     Console.WriteLine(string.Format("Value calling: {0}", cadena.Value));
  11:     //... que no llamemos al valor
  12:     Console.WriteLine(string.Format("isValueCreated: {0}", cadena.IsValueCreated));
  13:  
  14:     Console.Read();
  15: }

El constructor de System.Lazy<T> soporta las siguientes sobrecargas:

   1: public Lazy();
   2: public Lazy(Func<T> valueFactory);
   3: public Lazy(bool isThreadSafe);
   4: public Lazy(Func<T> valueFactory, bool isThreadSafe);

El parámetro isThreadSafe se establecerá a true cuando necesitemos utilizar el objeto de forma concurrente por multiples threads, con valor predeterminado a false.

El parámetro valueFactory es un delegado del tipo Func<T> y será el encargado de inicializar el valor del objeto Lazy. Un ejemplo, además del expuesto en el ejemplo anterior, podría ser:

   1: public class Order {}
   2:  
   3: public class OrderDb
   4: {
   5:     public static List<Order> GetOrdersBy(string idCustomer)
   6:     {
   7:         return new List<Order>
   8:                    {
   9:                        new Order(),
  10:                        new Order(),
  11:                        new Order()
  12:                    };
  13:     }
  14: }
  15:  
  16: public class Customer
  17: {
  18:     public Lazy<List<Order>> _orders;
  19:  
  20:     public Customer(string id)
  21:     {
  22:         //inicialización Lazy
  23:         _orders =new Lazy<List<Order>>(() =>  OrderDb.GetOrdersBy(id) );
  24:     }
  25: }

Con el siguiente programa de consola:

   1: class Program
   2: {
   3:     static void Main(string[] args)
   4:     {
   5:         Customer customer = new Customer("10");
   6:  
   7:         //pese a que customer se ha incializado la Lista de Orders aún no:
   8:         Console.WriteLine(string.Format("isValueCreated: {0}", customer._orders.IsValueCreated));
   9:         //Solicitamos las ordenes
  10:         Console.WriteLine(string.Format("calling Value.Count: {0}", customer._orders.Value.Count));
  11:         //Ahora si se han instanciado
  12:         Console.WriteLine(string.Format("isValueCreated: {0}", customer._orders.IsValueCreated));
  13:  
  14:         Console.Read();
  15:     }
  16: }

Cuya salida será:

image

Es importante tener en mente este tipo de inicializaciones sobre todo en procesos de mucho consumo de recursos, por ejemplo objetos de la capa de datos que almacenan datos binarios – imagen, video,-  y que muchas veces no necesitamos que consuman memoria si no se van a utilizar. Como este ejemplo, muchos más…

Ejemplo de Sync entre Oracle y SQL Server Compact

Publicado en MSDN Code Gallery nuevo ejemplo de entorno de sincronización para orígenes de datos Oracle 10g o superior con SQL Server Compact en modo peer-to-peer. Lo más destacado de este ejemplo es el modo de creación del proveedor específico para Oracle a través de la clase DbSyncProvide. Peses a que el ejemplo utiliza SQL Server Compact, podemos hace uso tanto del nuevo proveedor específico para SQL Server Express, incluido en MS Sync Framework 2.0, como SQL Server.

Al pan Enum y al vino Flags

Mientras preparaba el material para el WebCast que di para el dotNet Club de la U. Lleida, me tope con enumeradores como marcadores de bit y quiero comentar lo útil que pueden llegar a ser.

Básicamente tenemos dos opciones o características que determinan el comportamiento de este tipo de dato constante y se basa en el uso o no del atributo FlagAttribute sobre el Enum. Es importante entender que dicho atributo será especialmente útil cuando necesitemos que los valores del enumerador se combinen a través de operaciones lógicas o bit a bit del tipo AND, OR, NOT y XOR.

Un ejemplo de típica declaración de enumeradores seria:

   1: public enum TypicalEnums
   2: {
   3:     Option1, // = 0x00
   4:     Option2, // = 0x01
   5:     Option3, // = 0x02
   6:     Option4, // = 0x03
   7:     Option5, // = 0x04
   8:     Option6  // = 0x05
   9: }

En este ejemplo, damos por supuesto que una variable de tipo TypicalEnums únicamente podrá contener un único valor, cuyo tipo subyacente es por defecto es int. Sin embargo el siguiente enumerador:

   1: [Flags]
   2: public enum FlagEnums
   3: {
   4:     Option0 = 0x00,     // 0 = 0x00
   5:     Option1 = 0x01,     // 1 = 0x01
   6:     Option2 = 0x01 << 1,// 2 = 0x02
   7:     Option3 = 0x01 << 2,// 4 = 0x04
   8:     Option4 = 0x01 << 3,// 8 = 0x08
   9:     Option5 = 0x01 << 4,//16 = 0x16
  10:     Option6 = 0x01 << 5 //32 = 0x32
  11: }

Nos permitirá tener varios valores dentro de una misma variable del tipo FlagsEnums.

En el primer caso podremos hacer por ejemplo:

Cliente.Tipo = TypicalEnums.Option1 | TypicalEnums.Option2

Pero no tendrá ninguna repercusión pues Cliente.Tipo almacenará el valor 1 (TypicalEnums.Option1), pero sin embargo la siguiente sentencia:

Cliente.Caracteristicas = FlagEnums.Option2 | FlagEnums.Option5,

Si que almacenará ambas opciones.

Fijaros que en la declaración de FlagsEnum hemos indicado explícitamente el valor de las opciones de tres formas, desplazando un bits a la izquierda en base al valor 0x01, con valores numéricos decimales y valores hexadecimales. Todos ellos tendrán la siguiente correspondencia en binario:

  • Option0 = 0000000
  • Option1 = 0000001
  • Option2 = 0000010
  • Option3 = 0000100
  • Option4 = 0001000
  • Option5 = 0010000
  • Option6 = 0100000

A partir de aquí todo lógica. Si en el anterior ejemplo asignamos FlagsEnum.Option2 y FlagsEnum.Option5 al campo Cliente.Característica el valor que almacenará será 7 es decir 2 + 5, y por tanto utilizaremos el operador lógico OR:

   1: Cliente cliente = new Cliente
   2:                       {
   3:                           IdProvincia = 1,
   4:                           Tipo = TypicalEnums.Option1, 
   5:                           Caracteristicas = FlagEnums.Option2 | FlagEnums.Option5,
   6:                           //Caracteristicas = 00000010        | 00001000           = 00001010
   7:                           Nombre = "Cliente 1",
   8:                           VolumenNegocio = 10.0m
   9:                       };

Ahora bien,¿cómo podemos sacar el máximo provecho de los enumeradores con marcadores de bit? pues aplicando lógica, es decir, si queremos saber si un marcador se ha establecido utilizaremos AND:

   1: if ((cliente.Caracteristicas & FlagEnums.Option5) == FlagEnums.Option5)
   2:     // (00001010 & 00001000) = 00001000 
   3:     //             00001000  = 00001000 => true
   4:     Console.WriteLine("{0}: \nFlagEnum \t[{1}] \nOption 5 \t[{2}] \nHence: \t\t[{3}]",
   5:                       cliente.Nombre,
   6:                       Convert.ToString(((int)cliente.Caracteristicas), 2),
   7:                       Convert.ToString(((int)FlagEnums.Option5), 2),
   8:                       Convert.ToString((int)(cliente.Caracteristicas & FlagEnums.Option5), 2));

Como puedes ver, en la condición de la sentencia if estamos comprobando la existencia de FlagsEnums.Option5 de forma lógica. Realizamos la operación lógica a nivel de bit de Cliente.Característica AND FlagsEnums.Option5 e igualamos al valor de FlagsEnums.Option5. Por otro lado:

   1: if ((cliente.Caracteristicas & FlagEnums.Option4) != FlagEnums.Option4)
   2:     // (00001010 & 00000100) = 00000100 
   3:     //             000000000 = 00000100 => false
   4:     Console.WriteLine("Cliente with \nFlagEnum \t[{0}] \nhasn't Option 4 \t[{1}]",
   5:         Convert.ToString(((int)cliente.Caracteristicas), 2),
   6:         Convert.ToString(((int)FlagEnums.Option4), 2));

Si queremos comprobar FlagsEnums.Option4, el cual no está, el razonamiento será el mismo (fíjate en las líneas 2 y 3). Tras ejecutar ambos Snippets con la clase Cliente definida como:

   1: public class Cliente
   2: {
   3:     public int IdProvincia { get; set; }
   4:     public TypicalEnums Tipo { get; set; }
   5:     public FlagEnums Caracteristicas { get; set; }
   6:     public string Nombre { get; set; }
   7:     public decimal VolumenNegocio { get; set; }
   8:  
   9:     public override string ToString()
  10:     {
  11:         return string.Format("Cliente: {0} - Provincia:{1} - \nTipo: {2} - Caract:{3} - Vol.:{4}e\n",
  12:                              Nombre, IdProvincia, (int) Tipo,Caracteristicas, VolumenNegocio);
  13:     }
  14: }

Obtendremos:

image

Por último, si pretendemos quitar un marcador ya establecido utilizaremos un XOR de forma que:

cliente.Caracteristicas = cliente.Caracteristicas ^ FlagEnums.Option5;

Desasignaría FlagsEnums.Option5 al campo Cliente.Características.

Uso de métodos extensores

Soy un auténtico fan de este tipo de característica y no puedo dejar pasar ni un solo enumerador de marcadores de bit sin extender el típico método HasFlag o como_queráis_llamarlo a la clase que los utiliza, siempre y cuando sea posible, y por tanto una forma de extender la clase Cliente para la comprobación de marcadores seria la que he utilizado para confeccionar el ejemplo de este post, es decir:

   1: public static class ClienteExtensions
   2: {
   3:     public static string HasFlagVerbose(this Program.Cliente cliente, Program.FlagEnums flag)
   4:     {
   5:         return string.Format("Checking {2} for {0}: \nCaracteristica \t[{1}] \n{2} \t[{3}] \nHence \t\t[{4}]\n",
   6:                              cliente.Nombre,
   7:                              Convert.ToString(((int)cliente.Caracteristicas), 2).PadLeft(8, '0'),
   8:                              flag,
   9:                              Convert.ToString(((int)flag), 2).PadLeft(8, '0'),
  10:                              Convert.ToString((int)(cliente.Caracteristicas & flag), 2).PadLeft(8, '0'));
  11:     }
  12:  
  13:     public static bool HasFlag(this Program.Cliente cliente, Program.FlagEnums flag)
  14:     {
  15:         return (cliente.Caracteristicas & flag) == flag;
  16:     }
  17: }

Con lo que el cuerpo del programa que he ejecutado para mostrar los resultados seria:

   1: public class Program
   2:     {
   3:         
   4:         static void Main(string[] args)
   5:         {
   6:             Cliente cliente = new Cliente
   7:                                   {
   8:                                       IdProvincia = 1,
   9:                                       Tipo = TypicalEnums.Option1, 
  10:                                       Caracteristicas = FlagEnums.Option2 | FlagEnums.Option5,
  11:                                       //Caracteristicas = 00000010        | 00001000           = 00001010
  12:                                       Nombre = "Cliente 1",
  13:                                       VolumenNegocio = 10.0m
  14:                                   };
  15:  
  16:             //comprobamos q realmente tiene FlagEnums.Option5 
  17:             if ((cliente.HasFlag(FlagEnums.Option5)))
  18:                 Console.WriteLine(cliente.HasFlagVerbose(FlagEnums.Option5));
  19:  
  20:             //comprobamos q realmente NO tiene FlagEnums.Option4
  21:             if (!(cliente.HasFlag(FlagEnums.Option4)))
  22:                 Console.WriteLine(cliente.HasFlagVerbose(FlagEnums.Option4));
  23:  
  24:             //quitamos FlagsEnums.Option5
  25:             cliente.Caracteristicas = cliente.Caracteristicas ^ FlagEnums.Option5;
  26:  
  27:             //comprobamos q hemos quitado FlagEnums.Option5
  28:             if (!(cliente.HasFlag(FlagEnums.Option5)))
  29:                 Console.WriteLine(cliente.HasFlagVerbose(FlagEnums.Option5));
  30:  
  31:             Console.ReadKey();
  32:         }
  33:     }

 

A partir de aquí… posibilidades infinitas ;-))

Más info:

Actualizando HTC Dream de Movistar a Cupcake (Android 1.5)

Pues ejerciendo el falso y sobrevalorado “derecho” de Canje de Puntos después de contribuir durante más dos años a aumentar las arcas de Telefónica para que, cada vez más vayan subsituyendo mano de obra en los departamentos de atención telefónica por maquinaria automática absurda, adquirí el viernes, y no voy a entrar a explicaros todos los pasos que he realizado para conseguirlo, pues empezaría a blasfemar, un HTC Dream tras pagar 239pavos e hipotecar mi futuro dos años con Movistar.

La decisión de compra se debió a que mi flamante HTC HD con Windows Mobile tuvo un pequeño percance. Mi relación con el soporte técnico de HTC no lo detallaré pues convertiría este post en un manifiesto anti-multinacionales tecnológicas.

La cuestión es que tras empezar a utilizar el HTC Dream de Movistar y familiarizarme un poco con Android (gracias al  Centro de Soporte Telefónico del Maestro Alejandro Mezcua ;-) ) me cercioré de que la versión de Android que suministra este terminal, además de estar basado en Android 1.1, está algo capada. Por ejemplo, no puedo sincronizar contactos. Manda huevos. Buscando, encontré en http://and.roid.es un post de un tal Rick el cual explicaba paso por paso la actualización del HTC Dream de Movistar a Cupcake con lo que me puse manos a la obra.

Escribo este post para animar a los que no están muy seguros de si actualizar o no. En comparación, tras instalar Android 1.5, encuentro, además de la posibilidad de sincronización de Agenda, Contactos y Correo (menos mal), muchas otras aplicaciones que no vienen de serie, como por ejemplo uso de la Videocámara, además de algún Widget que otro. Además en el propio proceso de actualización se actualiza la radio (firmware), lo cual sí he notado, especialmente en cobertura.

Actualización

Seguid los pasos tal y como indica Rick en su post. Únicamente hay una error en la combinación de teclas que enumera para reiniciar el dispositivo en Fastboot, que es Home+Back en lugar de alt + back. Aseguraros de descargaros todos los componentes antes de todo. La guía hace referencia al SDK del Android 1.5 r1 y la última es la r3, pero es trivial.

Recomendable descargarse el FastBoot desde la Web de HTC e instalarla en un directorio de la raíz, al poder ser dentro de un subdirectorio del SDK pues se tiene que ejecutar desde la línea de comandos.  Tras reiniciar el dispositivo en modo FastBoot no te resultará muy difícil seguir las instrucciones pues además de estar en castellano las opciones son claras. Si no quieres reiniciar el dispositivo en varias ocasiones y debido a que tienes que utilizar la SD para copiar los archivos update.zip (del cupcake y del firmware) no estaría de más tener un lector de tarjetas microSD he ir copiando y/o renombrando archivos.

No olvidéis actualizar el firmware. Yo me equivoqué y descargué y renombre un archivo zip de recursos el cual tenia la radio, con lo que tras ejecutarlo con Fastboot me dio un error; únicamente hay que comprimir en update.zip la carpeta radio.

Tras la actualización del cupcake y de la radio, no tuve que hacer nada más si utilizas la ROM de Ricky. El teclado funcionan perfectamente y la conexión APN de movistar viene configurada.

Publicado por José Miguel Torres | 2 comment(s)
Archivado en:

SQL Server –> Sync <- SQL Azure = Proyecto Huron muestra sus cartas!

Ayer se presentó en el SQL Pass Conference, en Seattle, las primeras imágenes del proyecto “Huron” el cual permitirá la sincronización de orígenes de datos SQL Server con SQL Azure.

En breve, Microsoft pondrá a disposición del público la primera CTP así como un add-in para SQL Server Management Studio. La idea es proporcionar un Wizard para la creación de un contexto de sincronización para que posteriormente SQL Agent sea el encargado de ejecutar las sincronización de ambos proveedores.

Probablemente el próximo PDC hayan más noticias.

Aquí van una imágenes.

GroupBy con LINQ to Objects

El agrupamiento de un conjunto de datos mediante LINQ, ya sea mediante la extensión de IEnumerable o IQueryable, tiene una serie de características las cuales me gustaría comentar aquí.

Para explicar un poco las posibilidades del agrupamiento mediante la extensión GroupBy voy a exponer un ejemplo con LINQ to Objects y para ello, primero, definiremos una clase sencilla que represente la entidad Cliente.

public class Cliente
{
public int IdProvincia { get; set; }
public int Tipo { get; set; }
public string Nombre { get; set; }
public decimal VolumenNegocio { get; set; }

public override string ToString()
{
return string.Format("\t\t-> Cliente: {0} - Provincia:{1} - Tipo: {2} - Vol.:{3}e\n",
Nombre, IdProvincia, Tipo,VolumenNegocio);
}
}

Como se puede observar no es más que una clase con 4 propiedades implícitas y el método ToString() sobrescrito para poder mostrar por la consola la información de un objeto iterado del tipo Cliente.

Vamos a generar una lista de clientes mediante una lista genérica de la siguiente forma:

//inicializamos lista de clientes
var list = new List<Cliente>
{
new Cliente {IdProvincia = 1, Nombre = "Cliente1", Tipo = 10, VolumenNegocio = 100.00m},
new Cliente {IdProvincia = 2, Nombre = "Cliente2", Tipo = 20, VolumenNegocio = 20.00m},
new Cliente {IdProvincia = 3, Nombre = "Cliente3", Tipo = 20, VolumenNegocio = 230.00m},
new Cliente {IdProvincia = 3, Nombre = "Cliente4", Tipo = 20, VolumenNegocio = 500.00m},
new Cliente {IdProvincia = 1, Nombre = "Cliente5", Tipo = 30, VolumenNegocio = 10.00m},
new Cliente {IdProvincia = 2, Nombre = "Cliente6", Tipo = 10, VolumenNegocio = 750.00m},
new Cliente {IdProvincia = 1, Nombre = "Cliente7", Tipo = 20, VolumenNegocio = 340.00m},
new Cliente {IdProvincia = 1, Nombre = "Cliente8", Tipo = 20, VolumenNegocio = 170.00m}
};

La intención es agrupar esta lista de clientes por la provincia, a la cual pertenecen, a través de la propiedad IdProvincia del tipo int. Para ello, en primer lugar, echaremos un vistazo a la extensión GroupBy que incorpora la clase System.Linq.Enumerable. Dicha extensión presenta las siguientes sobrecargas:

public static IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>
(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector);

public static IEnumerable<TResult> GroupBy<TSource, TKey, TResult>
(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
Func<TKey, IEnumerable<TSource>, TResult> resultSelector);

public static IEnumerable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>
(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
Func<TSource, TElement> elementSelector);

public static IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>
(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
IEqualityComparer<TKey> comparer);

public static IEnumerable<TResult> GroupBy<TSource, TKey, TResult>
(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
Func<TKey, IEnumerable<TSource>, TResult> resultSelector,
IEqualityComparer<TKey> comparer);

public static IEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult>
(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
Func<TSource, TElement> elementSelector,
Func<TKey, IEnumerable<TElement>, TResult> resultSelector);

public static IEnumerable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>
(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
Func<TSource, TElement> elementSelector,
IEqualityComparer<TKey> comparer);

public static IEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult>
(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
Func<TSource, TElement> elementSelector,
Func<TKey, IEnumerable<TElement>, TResult> resultSelector,
IEqualityComparer<TKey> comparer);

En todas ellas existen un denominador común, el parámetro keySelector del tipo Func<TSource, TElement> que determina el valor de tipo TKey por el cual se agrupara la lista. Por otro lado GroupBy puede retornar un objeto del tipo IEnumerable<TSource> si se especifica el parámetro resultSelector (tipo Func<TSource, TKey>) o bien un objeto del tipo IEnumerable<IGroupingKey<TKey, TElement>> para todos los demás. Vamos  centrarnos en éste último por ahora.

Manejando resultados IEnumerable<IGroupingKey<TKey, TElement>>

Si el agrupamiento se realiza sobre una lista de elementos iterativos o “IEnumerables” es obvio que el resultado, otra lista de subelementos agrupados por una clave del tipo TKey, sea otra lista de elementos iterativos de ahí que el tipo resultante sea IEnumerable<T>. La singularidad esta en el tipo genérico en la iteración del valor retornado el cual es del tipo IGroupingKey<TKey,TElement> y vamos a ver el porqué. Lo que LINQ hará ante un GroupBy es realizar un recorrido completo por la lista y seleccionará todos los elementos del tipo TElement de una misma clave (TKey). Por consiguiente el resultado será una lista del agrupamiento de elementos definidos por la interfaz IGroupingKey<TKey,TElement>, en la que almacenará la clave y el conjunto de elemento agrupados por el valor de dicha clave, respetivamente en cada tipo genérico. Veamos un ejemplo.

En nuestra lista de clientes vamos a agrupar los elementos por el identificador de provincia definido por Cliente.IdProvincia.  Para ello definiremos una variable del tipo IEnumerable<IGroupingKey<int,Cliente> pues el tipo de datos de agrupamiento es del tipo int (propiedad IdProvincia) y el elemento a agrupar es del tipo Cliente, por tanto:

IEnumerable<IGrouping<int, Cliente>> groupByProv = 
from cliente in list group cliente by cliente.IdProvincia;

O lo que es lo mismo:

var groupByProv = list.GroupBy(cliente => cliente.IdProvincia);

Ahora la variable groupByProv posee una lista de todas las clave/agrupaciones realizadas. De hecho podemos comprobarlo de la siguiente forma:

foreach (var cProv in groupByProv)//cProv es del tipo IEnumerable<IGrouping<int, Cliente>>
{
Console.WriteLine(
string.Format("Provincia {0}, {1} clientes", cProv.Key, cProv.Count()));
}

Cuyo resultado por pantalla seria:

image

La variable implícita cProv posee tanto la clave utilizada (IdProvinicia) como la iteración de los clientes agrupados por dicha propiedad, de forma que podría ser recorrida de igual forma.

foreach (var cProv in groupByProv)//cProv es del tipo IEnumerable<IGrouping<int, Cliente>>
{
Console.WriteLine(
string.Format("Provincia {0}, {1} clientes", cProv.Key, cProv.Count()));

foreach(var cliente in cProv)
Console.WriteLine(cliente.ToString());
}

Y el resultado:

image

Sin embargo podríamos rizar aún más el rizo y agrupar, de nuevo, cada una de las agrupaciones por el tipo de cliente. De esta forma tendríamos una primera agrupación según la IdProvincia del cliente y por cada uno, una agrupación por tipo de cliente de la siguiente forma:

   1: foreach (var cProv in groupByProv)//cProv es del tipo IEnumerable<IGrouping<int, Cliente>>
   2: {
   3:     Console.WriteLine(string.Format("Provincia {0} ", cProv.Key));
   4:  
   5:     IEnumerable<IGrouping<int, Cliente>> groupByTipo = cProv.GroupBy(cliente => cliente.Tipo);
   6:  
   7:     foreach (var cTipo in groupByTipo)
   8:     {
   9:         Console.WriteLine(string.Format("\tTipo {0} \n", cTipo.Key));
  10:  
  11:         foreach (var cliente in cTipo)
  12:             Console.WriteLine(cliente.ToString());
  13:     }
  14: }

Lo que hemos hecho en el ejemplo anterior es aprovechar la iteración del primer agrupamiento para volver a generar un extensión GroupBy pero en esta ocasión con la propiedad Cliente.Tipo (int) como TKey. El resultado:

image

Manejando resultados IEnumerable<TSource>

Como comenté anteriormente, GroupBy puede devolver una iteración de tipo IEnumerable<TSource> indicando en la sobrecarga el parámetro resultSelector. Para ver este ejemplo, en base a la lista de cliente generada anteriormente, vamos a mostrar, por ejemplo, para cada una de las provincias (agrupamiento) el número total de clientes, el valor máximo, mínimo y medio de la propiedad Cliente.VolumenNegocio (decimal) de modo que nos ofrecerá información, por cada provincia, de los valores máximo, mínimo y medio del volumen de negocio de los clientes.

Para ello utilizaremos la sobrecarga:

   1: System.Linq.Enumerable.GroupBy<TSource, TKey, TResult>(
   2:    this System.Collections.Generic.IEnumerable<TSource>, 
   3:    System.Func<TSource,TKey>, 
   4:    System.Func<TKey,System.Collections.Generic.IEnumerable<TSource>,TResult>)
La implementación será:
   1: var groupByInfo = list.GroupBy(
   2:     cliente => cliente.IdProvincia, //seguimos con el agrupamiento por provinicia
   3:     (provincia, clientes) => new //retornamos un tipo anónimo
   4:         {
   5:             //con info sobre el agrupamiento
   6:             Key = provincia,
   7:             Count = clientes.Count(),
   8:             Min = clientes.Min(c => c.VolumenNegocio),
   9:             Max = clientes.Max(c => c.VolumenNegocio),
  10:             Avg = clientes.Average(c => c.VolumenNegocio)
  11:         });

El primer lugar, el tipo de la iteración de retorno es del tipo anónimo y es por ello que nos basamos en una variable implícitamente tipada (var). El primer parámetro (línea 2) es del tipo keySelector que vimos anteriormente y como dije es común en todas las sobrecargas pues es el valor clave de agrupamiento. Seguidamente el segundo parámetro (líneas 3-11), del tipo Func<int,IEnumerable<Cliente>,anonymous type> es donde se proyectará el resultado del agrupamiento.

Iteramos y mostramos los resultados.

   1: foreach (var res in groupByInfo)
   2:     Console.WriteLine(
   3:         string.Format("Provinicia:{0}\n\tCount:{1}\n\tMin Volumen:{2}\n\tMax Volumen:{3}\n\tAvg:{4}"
   4:                       , res.Key, res.Count, res.Min, res.Max, res.Avg));

En total 3 iteraciones con sus respectivas “estadísticas”:

image

El código completo:

namespace LINQGroupingBy
{
using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
static void Main(string[] args)
{
//Ejemplo para LINQ to Objects

//inicializamos lista de clientes
var list = new List<Cliente>
{
new Cliente {IdProvincia = 1, Nombre = "Cliente1", Tipo = 10, VolumenNegocio = 100.00m},
new Cliente {IdProvincia = 2, Nombre = "Cliente2", Tipo = 20, VolumenNegocio = 20.00m},
new Cliente {IdProvincia = 3, Nombre = "Cliente3", Tipo = 20, VolumenNegocio = 230.00m},
new Cliente {IdProvincia = 3, Nombre = "Cliente4", Tipo = 20, VolumenNegocio = 500.00m},
new Cliente {IdProvincia = 1, Nombre = "Cliente5", Tipo = 30, VolumenNegocio = 10.00m},
new Cliente {IdProvincia = 2, Nombre = "Cliente6", Tipo = 10, VolumenNegocio = 750.00m},
new Cliente {IdProvincia = 1, Nombre = "Cliente7", Tipo = 20, VolumenNegocio = 340.00m},
new Cliente {IdProvincia = 1, Nombre = "Cliente8", Tipo = 20, VolumenNegocio = 170.00m}
};


//obtenemos todos los clientes agrupados por provincias
var groupByProv = list.GroupBy(cliente => cliente.IdProvincia);

//tambien se puede expresar como:
//
//IEnumerable<IGrouping<int, Cliente>> groupByProv =
// from cliente in list group cliente by cliente.IdProvincia;

foreach (var cProv in groupByProv)//cProv es del tipo IEnumerable<IGrouping<int, Cliente>>
{
Console.WriteLine(
string.Format("Provincia {0}, {1} clientes", cProv.Key, cProv.Count()));

foreach(var cliente in cProv)
Console.WriteLine(cliente.ToString());
}

Console.ReadKey();

foreach (var cProv in groupByProv)//cProv es del tipo IEnumerable<IGrouping<int, Cliente>>
{
Console.WriteLine(string.Format("Provincia {0} ", cProv.Key));

IEnumerable<IGrouping<int, Cliente>> groupByTipo = cProv.GroupBy(cliente => cliente.Tipo);

foreach (var cTipo in groupByTipo)
{
Console.WriteLine(string.Format("\tTipo {0} \n", cTipo.Key));

foreach (var cliente in cTipo)
Console.WriteLine(cliente.ToString());
}
}

Console.ReadKey();
Console.Clear();

//volvemos a agrupar
var groupByInfo = list.GroupBy(
cliente => cliente.IdProvincia, //seguimos con el agrupamiento por provinicia
(provincia, clientes) => new //retornamos un tipo anónimo
{
//con info sobre el agrupamiento
Key = provincia,
Count = clientes.Count(),
Min = clientes.Min(c => c.VolumenNegocio),
Max = clientes.Max(c => c.VolumenNegocio),
Avg = clientes.Average(c => c.VolumenNegocio)
});

//mostramos los resultados
foreach (var res in groupByInfo)
Console.WriteLine(
string.Format("Provinicia:{0}\n\tCount:{1}\n\tMin Volumen:{2}\n\tMax Volumen:{3}\n\tAvg:{4}"
, res.Key, res.Count, res.Min, res.Max, res.Avg));

Console.ReadKey();

}

public class Cliente
{
public int IdProvincia { get; set; }
public int Tipo { get; set; }
public string Nombre { get; set; }
public decimal VolumenNegocio { get; set; }

public override string ToString()
{
return string.Format("\t\t-> Cliente: {0} - Provincia:{1} - Tipo: {2} - Vol.:{3}e\n",
Nombre, IdProvincia, Tipo, VolumenNegocio);
}
}
}
}
Publicado por José Miguel Torres | con no comments
Archivado en:

Nokia lleva a los tribunales al iPhone por violación de hasta 10 patentes

Y es que el 22 de octubre no sólo fue noticia el lanzamiento mundial de Windows 7. Nokia, por su parte, denunció ante los tribunales de EEUU a Apple por violar hasta 10 patentes que incorpora su teléfono móvil iPhone.

Por todos es sabido del liderazgo de Nokia en el mercado mundial de telefonia móvil, dónde practicamente 4 de cada 10 dispositivos vendidos en el mundo salen de la factoria finlandesa. Lo que probablemente no esté en la luz publica es que Nokia, quien ha llegado a invertir hasta 40 Billones de € en I+D, posee muchas de las patentes en telefonia móvil quién comparte con hasta 40 empresas del todo el mundo bajo contratos de colaboración.

Con todas excepto con Apple (supuestamente). Por lo visto los de Cupertino (California) han incorporado características al su dispositivo móvil al modo de Duty Free.  Encriptación, comunicaciones inhalambricas, seguridad o reconocimiento de voz son algunas de las patentes que (supuestamente) Apple ha violado.

Tambien cabe decir que Nokia ha presentado su primer semestre del año con datos negativos despues de más de una decada. Esta bajada se debe al mercado que ha conseguido tanto por el iPhone como su Marketplace y algunos expertos/analistas en mercados tecnologicos apunta a ésta como la causa principal de esta demanda.

De todas formas, el caso no se ejecutará hasta el 2011. A ver que pasará....

 

Publicado por José Miguel Torres | 1 comment(s)
Archivado en:

Microsoft Sync Framework 2.0 (Novedades de la nueva versión y adopción por SharePoint 2010 y Windows 7)

Se acaba de liberar la versión 2.0 de Microsoft Sync Framework. Esta esperadísima nueva versión de Sync Framework además de aportar nuevas características y mejorar (según dicen, habrá que probarlo) en cuanto a rendimiento, también es noticia por la adopción por parte de Windows 7 y Microsoft Office/SharePoint 2010.

Respecto a Windows 7, MS Sync Framework 2.0 será la plataforma de sincronización utilizada por Device Stage, nueva característica del sistema operativo que pretende ser el punto de conexión con los dispositivos móbiles. De modo que la sincronización de tareas, contactos y demás items se sincronizaran con cualquier orígenes de datos.

Por lo que respecta a SharePoint 2010, Sync Framework 2.0 jugará un papel importante en cuanto a la sincronización de Office Workspace (Groove) y SharePoint. Además, el propio servidor de SharePoint 2010 expondrá parte de las API de Sync Framework 2.0 para poder crear proveedores personalizados para integrar datos al propio SharePoint.

Sync Framework ofrece mejoras sustanciales respecto a la versión anterior:

Core Components

Sync Services for ADO.NET

  • Ahora ya sí (al fin) Sync Services for ADO.NET ofrece un proveedor de datos para SQL Server Express, además de los ya existentes SQL Server y SQL Server Compact. Para todos ellos con sus correspondientes adaptadores con lo que prácticamente no requeriremos escribir ningún comando de consulta o modificación.
  • Nueva API la sincronización de datos en batch, resolviendo los difíciles escenarios (en ocasiones irresolubles) que comportaba la utilización de batching en la versión 1.0. Además se ha optimizado de forma que podemos configurar el espacio máximo que un conjunto de cambios puede ocupar en memoria lo cual optimizará, y mucho, el rendimiento sobretodo en las inicializaciones de una sincronización. Esta característica será muy bien recibida por la comunidad .NET Compact Framework cuando aparezca la siguiente versión para dispositivo móviles.
  • Habilita las tareas de mantenimiento para por ejemplo limpiar los metadatos.
  • Dos opciones de inicialización de datos: inicialización  por sincronización normal (de una base de datos ya inicializada) o bien inicialización instantánea de una base de datos SQL Server Compact 3.5.

[OT] Tatuajes geeks

Impresionante documento trágico gráfico el que os traigo. En este mismo portal de geeks.ms se mostró no hace mucho una imagen de un tatuaje realmente curioso.

image

Pues por lo visto hay alguien que no se ha conformado únicamente con dos tag:

image

Incluso alguna ha hecho su propia interpretación:

image

Pero no solo de HTML vive el geek. Ahí va un poquito de C:

image image  
     

Y un “Hola Mundo!”

image

También hay lugar para los binarios:

image image  
     

 

Y un poco de código encriptado:

image 

Lo que tampoco podía faltar son los Fan Boys, empezando por los Linuxeros:

image image  
     

Pasando por los Appleros.

image image image
     

Googleros…

image image  
     

Yahooeros

image

Y por supuesto de los Microsofteros

image image  
     

Otros mas de principios, orgullosos de lo que son:

image

Los visionarios:

image

Los inconformista:

image

Bloggeros:

image image image
     

También tienen cabida “los del hierro” (hardware)

image

Y el mas de lo mas. Los auténticos geeks. Los que viven este mundillo como ninguno y sin duda uno de mis favoritos… los que se tatúan la Pantalla Azul de la Muerte en el brazo!!!! Que Grande!!!

image

En fín, ahí queda el tema.

Salud!

Publicado por José Miguel Torres | 5 comment(s)
Archivado en:

Del Modelo de Error Humano en las organizaciones TIC a los papanatas con corbata

 La industria aeronáutica invierte cada año una gran suma de dinero en una de las áreas más importantes, la seguridad. Pese a los fundamentos matemáticos y físicos en los que se basa la ingeniería aeronáutica, así como en otros campos de la ingeniería, los errores y los encadenamientos de actos de fortuitos suceden, lo que provocan grandes desastres casi siempre humanas.

Componentes electrónicos, mecánicos, computacionales, hidráulicos, una aeronave es un conjunto de dispositivos diseñados al milímetro dentro de una estructura física cuya finalidad no es únicamente la de volar, sino hacerlo de la forma más segura. Muchos de estos componentes y dispositivos, por no decir todos, requieren de un constante plan de mantenimiento para prevenir anomalías. Pese a ello, dichos componentes fallan y ante cualquier situación de fallida una aeronave puede seguir volando. El caso más conocido es el de los motores a reacción. Cualquier aeronave puede seguir volando si en pleno vuelo uno de los reactores deja de funcionar.

Pese a la alta fiabilidad de sus componentes, ocurren catástrofes aéreas dónde intervienen varios factores y de los cuales, además como piedra angular, la mayoría tienen como origen el factor humano. En realidad y a grosso modo se distinguen los siguientes factores:

  • Factores humanos a Más del 50%
    • Relacionados con el piloto
    • Otros
  • Factores meteorológicos
  • Factores mecánicos
  • Otros factores

clip_image002Más allá del dato puramente estadístico, lo que destaca es que más de la mitad de factores tienen un origen directamente humano. Los propios sistemas de equipamiento de la aeronave están diseñados para actuar y corregir dichos errores. Por ejemplo, los sistemas TCAS (Traffic alert and Collision Avoidance System) de las aeronaves son dispositivos que detectan, con antelación, peligro de colisión con otra aeronave en circulación equipada con TCAS. El TCAS no únicamente alerta sino que también propone una solución "negociada" con la otra aeronave (más concretamente con su TCAS) de forma que mientras a una aeronave le indicará que ascienda a la otra le indicara que descienda, evitando así la colisión. Por tanto estaríamos hablando de un sistema de defensa de errores provenientes de la persona, bien de los controladores aéreos o bien de los propios pilotos, por ejemplo.

En aeronavegación, todas las aeronaves en con rumbo entre 000 y 179 tienen una altitud o Nivel de Vuelo impar (FL330, FL350, FL370) y las aeronaves con rumbo entre 180-359 tienen un Nivel de Vuelo par (FL340, FL360, etc.). Básicamente y hablando en llano, nunca dos aeronaves chocaran "de frente" mientras estas se mantienen en altitud de crucero adecuado.

En base a esta regla básica de aeronavegabilidad, las colisiones cuando el avión está en altitud de crucero son sencillamente imposibles. Sin embargo durante esta fase (Crucero) es común el cambio del Nivel de Vuelo aumentándose o disminuyéndose según las condiciones meteorológicas o técnicas (ahorro de combustible) así como por razones ajenas e indicadas por el Control de zona (ATC) y es ahí dónde empiezan a haber los primeros riesgos, riesgos que se multiplican cuanto más cerca están de la fase de despegue o aproximación al aeropuerto de destino, debido al tráficos y a las variables de entorno.clip_image004

Si nos lo ponemos a pensar parece incrédulo que dos aviones comerciales choquen a más de 12.000 metros de altura en la fase de crucero y más con componentes como el TCAS ¿verdad?, pues desgraciadamente se han producido colisiones de aeronaves a una altitud de 36.000 pies (FL360).

El Modelo de Error Humano o Swiss Cheese Model

El modelo de error humano o Swiss Cheese Model fue acuñado por primera vez por el británico James T. Reason, quién es conocido cariñosamente como Swiss Cheese Man. Este modelo es utilizado en el análisis de riesgo de los sistemas humanos y también es conocido como el Efecto de Actos Acumulativos o el Modelo de Reason.

El Modelo de Error Humano parte de las premisas:

  • Los humanos no somos infalibles
  • Los errores son esperables

Es decir un error es una consecuencia de un acto preliminar (factores sistemáticos) no como un acontecimiento causal. En este modelo se representan las debilidades humanas como los agujeros de las lonchas del queso de gruyere catalogadas en cuatro niveles de errores:

  • Influencias organizacionales
  • Control de riesgos
  • Condiciones previas a actos inseguros
  • Los actos inseguros en sí

De esta forma, en el modelo se dibuja un escudo defensivo representadas por lonchas y cuyo objetivo no es el de desvelar quién se equivocó sino cómo y por que las defensas fallaron.

El uso metafórico del queso de gruyere no únicamente responde a la idea de las lonchas y sus agujeros y su representación, pues en dicho modelo los agujeros o debilidades humanas cambian, entre loncha y loncha, de forma, tamaño y posición y responden a la subjetividad de dichas debilidades. Gracias a esto se pueden prevenir “trayectorias lineales accidentales” debido a que se puede detectar una debilidad común en todas las defensas. La representación esquemática equivaldría a que de todas las lonchas de queso representando una capa de seguridad, todas tienen un punto común de debilidad por el que un acto casual puede ocurrir sin que haya ni una sola capa de seguridad que pueda evitarlo. Esto responde a errores o actos lineales.

El caso es que en un accidente intervienen diferentes factores y pese a que este modelo está ampliamente aceptado (es de origen psicológico), en muchos campos no únicamente de la ingeniería sino también de la medicina, los accidentes ocurren y cuando eso sucede tenemos la obligación de averiguar los factores que han fallado y han convergido en un desastre.

clip_image002[12]

Sistemas informáticos

La propia organización es la encargada de planificar y ejecutar sus propios sistemas de defensa y en la industria de la informática, de la misma forma que en otras industrias, dicha organización se sustenta en perfiles de mayor a menor responsabilidad. Ninguno de estos perfiles están exentos de responsabilidad y todos y cada uno de ellos forman una parte importante de los mecanismos de defensa.

clip_image009Es signo de fracaso las acusaciones de culpa por parte de los perfiles de más alta responsabilidad hacia los que están en la base del organigrama funcional de la organización. Son intolerables las tendencias a interpretar los actos de modo que confirmen las preconcepciones por parte de los perfiles de más alta responsabilidad dado que en la mayoría de los casos no son más intentos de exculpación. No debemos recordar nuestras propias decisiones como mejor de lo que realmente fueron y sobreestimarlas por encima del contexto de organización así como evitar el Efecto Foco, es decir desviar la predicción de resultados. En definitiva sesgar la información o los actos en base a prejuicios personales.

Contextualizando el Modelo de Error Humano en el ámbito informático, un error o falla es el resultado de la superposición de debilidades de los recursos humanos de una organización más las de la propia organización.

Como recursos humanos existen una multitud de categorías profesionales que abarcan desde los más experimentados (Arquitectos, Jefes de proyecto, Directores IT) a los recién licenciados/graduados (programadores/analistas junior, operadores). Todos y cada uno de ellos deben saber cuáles son sus limitaciones y responsabilidades y éstas deben ser tenidas en cuentas por las personas inmediatamente superior en el eslabón del organigrama organizativo y así sucesivamente. Cualquier acto producido que derive en una fallida debe ser contextualizado en base a si fue una equivocación (descuido, una distracción, una desconcentración, un error al seguir las reglas), un riesgo o un dolo.

clip_image011Las fallas de organización son aquellas cuyo origen las encontramos en el eslabón más alto del organigrama corporativo y la no actuación y prevención de estas fallas se propagan hacia los recursos inmediatamente inferiores del organigrama. Uno de los errores más graves que se cometen es el de la persuasión de recursos de nivel más bajo quedando impunes los de más alto nivel. Un error producido en un programador tiene su origen en los eslabones más altos de la organización. Todo esfuerzo dirigido al reconducir o castigar un recurso de bajo nivel bajo el pretexto de solución sin haber hecho lo propio desde un nivel más elevado, sencillamente será en vano.

Los orígenes de este tipo de fallas organizacionales se encuentran en el liderazgo. Se entiende como liderazgo como el conjunto de cualidades que definen el comportamiento de una persona y que intervienen positivamente en el ambiente laboral de un colectivo. Respeta y serás respetado.

Por otro lado, y siguiendo el hilo de fallas organizacionales, es importante crear una estructura jerárquica y equilibrada de mandos intermedios. Pese a que la experiencia es un grado, el "él lleva más tiempo que tú" es pretexto erróneo (sesgo). La selección y formación del personal así como la comunicación del mismo es uno de los procedimientos que menos importancia se les da, más son indirectamente improductivas y costosas. Por otra parte la calidad y el diseño de equipos así como las presiones operativas y/o comerciales de la propia organización con los clientes derivan en muchos casos, como factor de fallida de origen organizacional.

En busca del “TCAS” informático

Existen multitudes de mecanismos lógicos y físicos que debemos tener presente en todos los campos de las tecnologías de la información y comunicación. En caso del TCAS expuesto en la entradilla de este post tiene una interpretación libre dentro de nuestro campo. Cualquier componente lógico puede ayudarnos a evitar allí donde las debilidades humanas no pueden alcanzar pero también existen doctrinas dentro de la gestión de proyectos que contemplan nuestras limitaciones y las cuales TODAS se basan en la idea de equipo y perfiles y que abarcan y responde al termino CALIDAD.

Mi Opinión

Me preocupa especialmente la fabricación de ataúdes profesionales que algunos responsables de alto nivel llevan a cabo con sus subordinados debido a la falta de motivación y de formación. Esto deriva en una muerte lenta de la carrera profesional de los trabajadores que muchas veces olvidan la atención que  (especialmente en un campo dónde tan rápidamente evolucionan las tecnologías como lo es en el campo de la informática) el propio futuro profesional de un individuo requiere. Básicamente existen tres puntos en los que un empleado presta especial importancia por este orden:

  • Las pretensiones económicas
  • El ambiente de trabajo. Disfrutar con lo que se hace.
  • Su carrera profesional. Es decir la evolución personal dentro de su profesión.

Las descompensación exagerada de algunos de estos tres puntos (especialmente los dos últimos) será la sentencia a muerte (de su carrera profesional se entiende) de un empleado lo cual será catastrófico, primero para el propio empleado y segundo para la propia organización.

Pero, ¿Qué pasa con esos tipos de amplia experiencia que bajo la corbata dirigen y planifican la vida profesional de todos sus empleados?

En primer lugar, jamás sentiré más respeto por un compañero uniformado, por el simple hecho de serlo, que por otro cuya apariencia, sin ser violenta, esté fuera del estereotipo empresarial o social, esté por encima o no de mí. El respecto se gana con la confianza y la confianza se gana con oportunidades. En el momento en que un profesional empieza a tener mayores responsabilidades y mayor gente a su cargo automáticamente se otorga un rango de superioridad y poseedor de la verdad absoluta. Lo que dice él es lo correcto, porque lo dice él y por que la propia organización así permite ejercerlo. No hay lugar a discusión, su razón así como su responsabilidad, son superiores a los de los demás pero sin embargo (y curiosamente) es inversamente proporcional a sus excusas en caso de errores. El marrón se lo come el último y la verdad es que no se me ocurre nada más cobarde y ruin. Del que piensa y actúa así, no le deberé jamás ningún respeto.

Asumir las responsabilidades, defender a capa y espada a sus subordinados, confiar y respetar y recibir lo mismo, otorgar oportunidades y ayudar a descubrir sus debilidades y virtudes. Todo esto es trabajo humano, no productivo directamente pero que forja colectivos “indestructibles”, camaraderías de profesionales excelentes. El hoy por ti y mañana por mí. El “yo cubro tus espaldas”. El evitar el afán de protagonismo. Todo ello deriva en un EQUIPO. Un EQUIPO con mayúsculas pues se otorgan palabrerías de este tipo a colectivos que ni siquiera llegan a ser meros colegas profesionales sobre los que por encima suyo no hay más que un fósil profesional que oculta sus fracasos con su protagonismo inoportuno.

Si no se cumplen los requisitos humanos y éticos es imposible construir cualquier modelo de defensa. Sencillamente todo lo que toque dicha organización estará sentenciado a muerte y seguramente se llevará por delante a alguien (en el mejor de los casos).

 ¡Muerte a la hipocresía! ¡Viva el sacrificio!

Publicado por José Miguel Torres | 14 comment(s)
Archivado en:

¡Más de 200 asistentes registrados en el Code Camp Tarragona 2009!

Pues si, por encima de nuestras estimaciones iniciales, el Code Camp Tarragona 2009 se postula como uno de los eventos de comunidad más importantes del año 2009. Más de 30 sesiones y 30 speakers y con 9 patrocinadores y 3 colaboraciones el Code Camp Tarragon 2009 tiene todos los ingrendientes para ser todo un referente.

No hay escusas. Asistentes de Madrid, Sevilla, Galicia, Bilbao, Valencia, Malaga, Albacete,,, prácticamente desde todos los rincones de España van a estar con nosotros.

Un fin de semana en un Hotel de 4 estrellas en las espectaculares playas de La Pineda con los mayores expertos de .NET y de MONO de todo el país a nuestra disposición. ¿Que más podemos pedir?

¡Anímate y haznos compañia!

Más info: www.codecamp.es

 

 

Publicado por José Miguel Torres | 8 comment(s)
Archivado en:
Más artículos Página siguiente >