Integrar un video de YouTube en Silverlight 2

silveryoutubemini

 Me pareció tan curioso que me decidí a probarlo 😀 Es sabido, que no se puede insertar un componente Flash en Silverlight 2 … pero como comenta Ary Boretc se puede meter en un DIV flotante y colocarlo en la pantalla. Funciona bastante bien, aunque no funciona a pantalla completa (ya que en pantalla completa solo se puede ver la aplicación Silverlight) y tampoco funciona en Internet Explorer, intentaré averiguar porque 😛

Me faltaba entonces poder moverlo a voluntad como si fuese un elemento más en mi emulador de escritorio. El control que Ary propone, tiene unas propiedades para controlar la posición y el tamaño asi que simplemente es cuestión de “atar” el div al contenido de la ventana, todo gracias a TransformToVisual().

Cada ventana es un UserControl que acepta otro parametro como Content , asi que debia hacer que en todo momento el div ocupase la superficie de ese Content, tanto al moverlo como al redimensionarlo; aunque son elementos de mundos distintos, bailan sobre la misma superficie, un Canvas (en este caso una clase derivada), asi que simplemente se trata de obtener las coordenadas absolutas del Content con respecto al Canvas y aplicarselas al DIV flotante para controlar su posición, además de controlar también el tamaño, que ha de ser el mismo.

Lo primero creo un UserControl que será el contenedor virtual del video (digo virtual, porque realmente no contiene nada :P), y este control inicializa el control YouTubePlayer de Ary.

Siguiente, necesito acceder a la ventana para que me informe cada vez que el layout cambia. Creo que no hay una forma dada para escalar en el arbol visual buscando un Parent específico; yo cree un método extensor para este fin:

public static T GetParent<T>(this FrameworkElement element)
    where T : FrameworkElement
{
    while (element.Parent != null)
    {
        if (element.Parent is T)
            return (T)element.Parent;
        else
            element = element.Parent as FrameworkElement;
    }
    return null;
}

Una vez tengo el objeto ventana que contiene my UserContorl me subscribo a su evento LayoutUpdated. Este método extensor me vale también para encontrar el Canvas donde “bailan” los elementos, para poder obtener la posición relativa a este. Cada vez que la ventana se redimensione, se dispara el evento LayoutUpdated, pero no cuando se mueve, ya que lo que estoy modificando son las propiedades asociadas Canvas.Top y Canvas.Left, asi que me aseguraré de que cada vez que se mueve la ventana se llame a InvalidateMeasure() para se dispare el citado evento.

Ahora, en el manejador del evento LayoutUpdated que nos subscribimos, hay que actualizar la posición del DIV flotante cada vez que la ventana cambia. Dentro de mi UserControl, hay un control de tipo ContentControl  que he llamado YTContainer, que es donde el video deberá aparecer.  Gracias a TransformToVisual() podemos obtener cual es la posición relativa a un control de cualquiera de sus descendientes, aunque no sean descendientes directos, como es el caso (hay toda una jerarquia de Grids, ventanas y UserControl desde YTContainer al Canvas):

Point position = YTContainer.TransformToVisual(surface)
                           .Transform(new Point(0, 0));
 
player.Top = position.Y;
player.Left = position.X;
player.Width = YTContainer.ActualWidth;
player.Height = YTContainer.ActualHeight;

 De esa forma se que punto en el Canvas se corresponde con el punto relativo “0,0” de YTContainer, ya simplemente tengo que actualizar las propiedades del YoutubePlayer

Y nada más, se puede ver el resultado en mi emulador de escritorio. Investigaré porque no funciona en Internet Explorer.

Creo que también se puede hacer usando propiedades de dependencia y data binding…  

Integrar un video de YouTube en Silverlight 2| vtortola.NET

Gestor de ventanas (Window Manager) en Silverlight 2

silverwindow He creado un pequeño gestor de ventanas como libreria para Silverlight 2, que permite añadir cualquier FrameworkElement embebido en una ventana, que se puede mover (desde la barra de título), redimensionar (desde la esquina inferior derecha),  colapsar (botón _) y cerrar (botón X). Además las ventanas pueden ser ordenadas en cascada ó en mosaico.

La clase se llama SilverWindowManager, hereda de Canvas, y lo que hace es crear unos elementos llamados SilverWindow, que son UserControl, y conectar 5 eventos entre ventana y escritorio, dos del “escritorio” a la ventana para que se puedan realizar las acciones de mover y redimensionar, y 3 de la ventana al escritorio para informar cuando se activa ó cierra una ventana. SilverWindow usa el FrameworkElement que se le pasa en el constructor para rellenar su espacio de trabajo. Cualquier FrameworkElement es bueno, desde por ejemplo MediaElement para poner un video, como un UserControl, de hecho lo que este ejemplo abre cada vez es una nueva instancia de un UserControl llamado DummyUserCtrl que tiene un color de fondo aleatorio.

 

Hay una cosa con la que no estoy muy contento, y es el comportamiento de redimensionar, primero porque parece que redimensiona a menos velocidad de la que se mueve el puntero y no consigo ver por que, y segundo porque al moverse el puntero fuera de la zona de redimensionamiento mientras esta redimensionando, hace que el evento MouseLeftButtonUp pase en cualquier sitio… y al ser incomprensiblemente de tipo Direct en lugar de Bubbling (su homólogo en WPF también es Direct, pero además tiene un MouseUp de tipo Bubbling), si se libera sobre un TextBox ó Botón parece que se queda la acción enganchada hasta el siguiente “mouse up” porque el evento se corta en ese control. Asi que si alguien le echa un vistazo al código y ve el porque de estos problemas… le estaria muy agradecido si me lo dice 😀

El diseño no es muy allá, pero es que ni todavía me he puesto a utilizar Expression Blend 2… ni todavía estoy muy puesto en cuestiones de diseño gráfico 😀

Esta es mi 4º experimento con Silvelight 2, y la verdad es que esta bastante limitado con respecto a su hermano mayor WPF(con el que batallo dia a dia), se echan mucho de menos los estilos implícitos, los triggers, las opciones de databinding como ElementName y RelativeSource, la distribución de eventos, el botón derecho y central del ratón… los triggers… y supongo que habrá más cosas que no están… ya los iré echando en falta 😛 Pero bien lo vale por lo pequeño que es el runtime, me gusta bastante 😀

 

Gestor de ventanas (Window Manager) en Silverlight 2 | vtortola.NET

Ordenaciones personalizadas con LINQ

Esta mañana necesitaba ordenar los elementos de una tabla en función de uno de los campos, pero el problema era que la comparación no era alfabética ni similar, era en función de unos criterios propios; uno de los parámetros que aceptan los métodos extensores OrderBy, OrderByDescending, ThenBy and ThenByDescending es un IComparer<>, probé y funcionó, asignaba un peso a cada valor y luego comparaba en el método Compare los pesos de los dos parámetros de entrada, pero aún asi no me gustaba como quedaba, no me gustaba lo de tener que escribir una clase solo para este propósito… buscaba algo más… compacto… asi que con ayuda de mi compañero use un delegado anónimo primero que directamente devolvia el peso en TKey inferido como Int32, que es en lo que LINQ basaria la ordenación y luego lo substituí por una expresión lambda; es realmente interesante como LINQ te facilita la vida 😀

Este pequeño ejemplo ordena un DataTable en función de su columna “Country” asignando a cada valor un peso en Int32 y siendo este peso el que devuelve la expresión infiriendo TKey como Int32, que será en lo que LINQ base ordenación de los elementos. Anotar que el elemento que queramos que tenga más relevancia debe ser el de menos peso y el que menos el que más peso:

DataTable EmployeesByCountry = 
            EmployeesTable.AsEnumerable()
            //.OrderBy(delegate(DataRow Employee)
            .OrderBy(Employee =>
                {
                    switch(Employee.Field<String>("Country"))
                    {
                        case "Denmark":return 3;
                        case "France":return 2;
                        case "Ireland":return 4;
                        case "Spain":return 1;
                        case "UK":return 5;
                        default: return Int32.MaxValue;
                    }
                }).CopyToDataTable();

Aún así estoy seguro que habrá formas mejores y más sencillas de hacerlo. Evidentemente es mejor si tenemos un algorritmo que calcule el peso en lugar de tener que fijarlos “a capón” … pero hay situaciones… que no hay más remedio 😀

Ordenaciones personalizadas con LINQ| vtortola.NET

Update-Select en un DataTable con LINQ

Últimamente ya no escribo nada, estoy totalmente inmerso en el mundo LINQ con el C# 3.0 y LINQ de Octavio Hernandez y el LINQ en Action … y poco hay que contar que no este en libros ó en los cientos de blogs que llevan escribiendo sobre LINQ desde hace mucho tiempo. Aún asi por lo menos iré escribiendo alguna cosilla sobre LINQ aunque solo sea para que no se me olvide como hacer ciertas cosas y tener que volverlas a buscar 😛

Este es un ejemplo simple de como lanzar una consulta Update-Select con LINQ sobre un DataTable, apoyandonos en el ya famoso método extensor ForEach … (que según me ha comentado un compañero es posible que aparezca en la BCL próximamente), lo que hace es en cada DataRow que cumple con las condiciones dadas introduce en la columna “Initial” la primera letra del nombre… (nada complicado vamos xD)

EmployeesTable.AsEnumerable()
   .Where(EmployeeRow => !EmployeeRow.IsNull("Country") && 
                  EmployeeRow.Field<String>("Country") == "UK" &&
                  !EmployeeRow.IsNull("FirstName") &&
                  EmployeeRow.Field<String>("FirstName") != String.Empty)
   .ForEach(EmployeeRow => EmployeeRow.SetField<String>("Initial", 
                                EmployeeRow.Field<String>("FirstName").Substring(0, 1)));

También empezaré ahora a escribir sobre WPF… que me toca ponerme las pilas 😀

Update-Select en un DataTable con LINQ | vtortola.NET

Consumir un Webservice SSL

Mas sencillo de lo que imaginaba, se trata simplemente de definir el siguiente delegado System.Net.ServicePointManager.ServerCertificateValidationCallbackcon la funcion que se encarga de validar el certificado.

Por ejemplo:

System.Net.ServicePointManager.ServerCertificateValidationCallback =
    new System.Net.Security.RemoteCertificateValidationCallback(ValidateSSL);

Y escribimos el metodo:

static Boolean ValidateSSL(object sender, X509Certificate certificate, 
                           X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
    // Validar el certificado...
 
    // Un ejemplo tosco para aceptar cualquiera sin errores.
    return sslPolicyErrors == SslPolicyErrors.None;
}

 

Consumir un Webservice SSL | vtortola.NET

Cargar un tipo dinamicamente

dynamictypeproject

  Una aplicación modular suele ser una aplicación donde sus funcionalidades son opcionales, de forma que podemos quitar ó añadirlas según nos convenga. La aplicación solo sabe que va a tratar con instancias que cumplen un determinado contrato, ya sea cumpliendo con una interfaz ó determinado tipo base (usando clases abstractas). Estos contratos suelen estar en ensamblados que conocen las dos partes, de forma que la aplicación espera una instancia de clase que cumple el contrato definido en el ensamblado común, y el ensamblado “opcional” provee una instancia de clase que cumple dicho contrato, dicho contrato ó acuerdo mutuo indica a la aplicación como usar dicha instancia. En el ejemplo de solución de Visual Studio que se ve a la izquierda, LoadTypeTest sería la aplicación, Common el ensamblado compartido donde se definen los contratos y los tipos comunes, y LibraryTest donde se encuentra definida la clase, LoadTypeTest y LibraryTest tienen referenciado a Common, pero se desconocen entre ellos.

En en ensamblado común he definido una interfaz y un delegado, que definen la forma en que la instancia “desconocida” se va a relacionar con la aplicación:

public delegate void DataArrival_(String Data);
 
public interface ITestInterface
{
    String Name { get; }
 
    event DataArrival_ DataArrival;
 
    void SendData(String Data);
}

Si la clase que que implementamos cumpliendo esta interfaz, tiene un constructor por defecto, tenemos dos formas de cargar el tipo dinámicamente:

Reflection:

Assembly myAssembly = Assembly.LoadFrom("LibraryTest.dll");
ITestInterface test2 = myAssembly.CreateInstance("LibraryTest.LibraryTest") as ITestInterface;
test2.DataArrival += new DataArrival_(delegate(String Data)
{
    Console.WriteLine("Received: " + Data);
});
test2.SendData("Hello " + test2.Name + "!!");

Remoting:

ObjectHandle obj = Activator.CreateInstance("LibraryTest", "LibraryTest.LibraryTest");
ITestInterface test = obj.Unwrap() as ITestInterface;
test.DataArrival += new DataArrival_(delegate(String Data)
    {
        Console.WriteLine("Received: " + Data);
    });
test.SendData("Hello "+ test.Name +"!!");

En este contexto, nos valen ambos planteamientos por igual, ambos cargan la instancia en el mismo dominio de aplicación que la aplicación principal y su rendimiento es bastante similar, a excepción de la primera instancia que realiza Remoting, que parece que le cuesta un poco más:

image

Pero, cuando la instancia tiene un constructor parametrizado tendrémos que usar una mezcla de las dos, ya que para poder invocar un constructor específico debemos de proveer el tipo a Activator.CreateInstance, que por supuesto lo podemos extraer con Reflection; vamos a suponer que la calse “desconocida” espera dos parámetros, un Int32 y un DataTable (ojo con el orden de los parámetros):

Assembly myAssembly = Assembly.LoadFrom("LibraryTest.dll");
Type myType = myAssembly.GetType("LibraryTest.LibraryTest");
ITestInterface test = Activator.CreateInstance(myType,myIndex,myTable) as ITestInterface;
test.DataArrival += new DataArrival_(delegate(String Data)
    {
        Console.WriteLine("Received: " + Data);
    });
test.SendData("Hello " + test.Name + "!!");

Pero… y si ni siquiera supiesemos que número de parámetros tiene el constructor… o que tipo de parámetros son… pues con Reflection podemos interrogar al tipo para que nos de información sobre los constructores que hay en la clase y sus respectivos parámetros. Un ejemplo un poco tosco :

Assembly myAssembly = Assembly.LoadFrom("LibraryTest.dll");
Type myType = myAssembly.GetType("LibraryTest.LibraryTest");
 
// Interrogo al tipo para comprobar si existe el constructor
// que necesito.
Object[] constructorParameters = null;
foreach (ConstructorInfo constructor in myType.GetConstructors())
{
    ParameterInfo[] parameters = constructor.GetParameters();
 
    if ((parameters[0].ParameterType == typeof(Int32)) &&
        parameters[1].ParameterType == typeof(DataTable))
    {
        constructorParameters = new Object[] {myIndex, myTable };
    }
    parameters.ToString();
}
 
ITestInterface test = Activator.CreateInstance(myType,constructorParameters) as ITestInterface;
test.DataArrival += new DataArrival_(delegate(String Data)
    {
        Console.WriteLine("Received: " + Data);
    });
test.SendData("Hello " + test.Name + "!!");

Como decía este es un ejemplo un poco tosco, podemos mejorar la lógica para detectar el constructor, ordenar los parámetros… etc.. etc..

Lo máximo que sabe la aplicación sobre la clase, es su nombre y en que ensamblado esta, cosas que le podemos pasar como parámetros ó tenerlo alojado en un archivo de configuración, de forma que alterando dicho archivo la aplicación usa una u otras funcionalidades. Y con esto e imaginación puedes hacer tus arquitecturas tan inteligentes y escalables como tu quieras, de forma que sean capaces de cargar tipos sin conocerlos previamente y usarlos por medio de una interfaz ó clase abstracta. Si a esto le añades el uso de atributos como metadatos para describir las clases… aún puedes conseguir cosas más inteligentes y escalables, a ver si tengo tiempo otro día para escribir sobre este tema, que es bastante apasionante 🙂

Cargar un tipo dinamicamente | vtortola.NET

Conversion de arrays sin cast directo con C#

Realizar casting entre clases es siempre sencillo, el inconveniente es cuando se trata de un arrays. Por ejemplo… sabiendo que la clase Manager deriva de Employee, si tenemos un array de Manager, es fácil convertirlo en un array de Employee usando casting directo:

Employee[] employees1 = (Employee[])managers;

Pero si tenemos un array de Employee no es posible convertirlo en  un array de Manager de la misma forma que tampoco podríamos hacer un casting directo entre objetos simples. No se me ocurre razón cuerda para querer hacer tal cosa, pero otro ejemplo más cotidiano puede ser cuando intentamos mostrar el contenido de un array en una línea usando String.Join, nos daremos cuenta que tiene que ser String[]. Existen muchas situaciones donde no hay un casting directo.

[more]

Afortunadamente disponemos del método genérico Array.ConvertAll<,> y del delegado genérico Converter<,> que nos pueden ayudar a simplificar estas cosas:

// Primero definimos como se convierte una clase en la otra
Converter<Employee, String> Employee2String = delegate(Employee m) { return m.Name; };
 
// Después convertimos todos los elementos del array usando ese delgado
String[] sArray = Array.ConvertAll<Employee,String>(Employees,Employee2String);

Ó podemos hacerlo en una sola línea aprovechando la inferencia de tipos:

String[] sArray = Array.ConvertAll<Employee,String>(Employees,delegate(Employee m) { return m.Name; });

 

Conversion de arrays sin cast directo con C# | vtortola.NET

Desechable o no desechable

La interfaz IDisposable nos provee del método .Dispose() que utilizamos para liberar los recursos que esta usando ese objeto, pero dicho método… no deja de ser un simple método 😉 Solo hace falta hacer una pequeña prueba para darse cuenta:

   1:  class Program
   2:  {
   3:      static void Main(string[] args)
   4:      {
   5:          Desechable test = new Desechable();
   6:            
   7:          test.Dispose();
   8:   
   9:          Console.WriteLine(test.Cadena??"Muerto"); // Muestra: Vivo!
  10:          Console.ReadKey(true);
  11:      }
  12:  }
  13:   
  14:  class Desechable : IDisposable
  15:  {
  16:      public String Cadena = "Vivo!";
  17:   
  18:      public void Dispose()
  19:      {
  20:   
  21:      }
  22:  }

Ok ok… un poco más complejo:

   1:  class Program
   2:  {
   3:      static void Main(string[] args)
   4:      {
   5:          Desechable test = new Desechable();
   6:          WeakReference wr = new WeakReference(test.Tabla.Columns[0]);
   7:   
   8:          test.Dispose();
   9:          test = null;
  10:   
  11:          Console.WriteLine(((DataColumn)wr.Target).ColumnName); // Muestra "Columna"
  12:          Console.ReadKey(true);
  13:      }
  14:  }
  15:   
  16:  class Desechable : IDisposable
  17:  {
  18:      public DataTable Tabla = new DataTable();
  19:   
  20:      public Desechable()
  21:      {
  22:          Tabla.Columns.Add(new DataColumn("Columna"));
  23:      }
  24:   
  25:      public void Dispose()
  26:      {
  27:          Tabla.Dispose();
  28:      }
  29:  }

El resultado cambia si en la línea 10 hacemos un GC.Collect() ;D

Como vemos, el único que puede liberar memoria en el .NET Framework es el Garbage Collector, por lo que el método .Dispose() no libera memoria in libera nada, solo nos sirve para asegurar que el objeto que estamos desechando ha cerrado correctamente todos sus recursos y podemos olvidarnos de él, ya se encargará el GC de liberar la memoria cuando lo crea necesario.

Entonces, implementar la interfaz IDisposable no hace nuestros objetos “destruibles” bajo demanda, ni setear todos los campos a null en Dispose no va a hacer que sea recolectado más deprisa, ni no hacerlo va a evitar que sea recolectado, ni debemos des-subscribir los eventos…

Por lo tanto, debemos implementar el patrón IDisposable en una clase siempre que:

  • Nuestra clase deriva de una clase que lo implementa.
  • Nuestra clase esta compuesta de otras clases que lo implementan.
  • Hagamos uso de recursos no administrados.

Para todo lo demás… mastercard confia en el GC 😀

Un tema que causa controversia en este aspecto es… ¿que pasa con los delegados? ¿Como el estar subscrito a delegados afecta a la recolección de memoria? Bien, el estar subscrito a un delegado de una clase, no afecta en su recolección:

   1:  class Program
   2:  {
   3:      static void Main(string[] args)
   4:      {
   5:          MiClase test = new MiClase();
   6:          WeakReference wr = new WeakReference(test);
   7:          
   8:          test.MiEvento += new EventHandler(test_MiEvento);
   9:   
  10:          test = null;
  11:          GC.Collect();
  12:   
  13:          Console.WriteLine(wr.IsAlive ? "Vivo" : "Muerto"); // Muestra "Muerto"
  14:          Console.ReadKey(true);
  15:      }
  16:   
  17:      static void test_MiEvento(object sender, EventArgs e)
  18:      {
  19:          throw new NotImplementedException();
  20:      }
  21:  }
  22:   
  23:  class MiClase
  24:  {
  25:      public event EventHandler MiEvento;
  26:  }

Pero al revés, es decir, que una clase este subscrita a uno de nuestros delegados… si provoca que el objeto no pueda ser recolectado:

   1:  class Program
   2:  {
   3:      static event EventHandler Evento;
   4:      static void Main(string[] args)
   5:      {
   6:          MiClase test = new MiClase();
   7:          WeakReference wr = new WeakReference(test);
   8:   
   9:          Evento += test.Manejador_Evento;
  10:   
  11:          test = null;
  12:          GC.Collect();
  13:   
  14:          Console.WriteLine(wr.IsAlive ? "Vivo" : "Muerto"); // Muestra "Vivo"
  15:          Console.WriteLine(Evento.GetInvocationList().Length); // Muestra 1
  16:          Console.ReadKey(true);
  17:      }
  18:  }
  19:   
  20:  class MiClase
  21:  {
  22:      public void Manejador_Evento(object sender, EventArgs e)
  23:      {
  24:          throw new NotImplementedException();
  25:      }
  26:  }

Y ojo, que los delegados son muy comodos para ejecutar muchos métodos de una pasada (por ejemplo podríamos tener una serie de objetos subscritos a un delegado y cada vez que invocaramos a este se ejecutaria ese método en todos los objetos), pero como veis pueden causar un memory leak; aunque en ese caso poco podemos hacer desde el método Dispose ya que es otra clase la que ha de desuscribirse.

Saludos desde el frio Dublin donde el Verano es una broma de mal gusto.

Desechable o no desechable| vtortola.NET

Constructores, inicializacion rapida de objetos y C# 3.0

La inicialización rápida de objetos es una nueva e interesante característica de C# 3.0, pero me gustaria reflexionar un poco sobre su uso y el de nuestros amigos los constructores.

Un constructor es el método de una instancia que implementa las acciones necesarias para inicializar la instancia de la clase, y es invocado por el operador new cuando instanciamos dicha clase.  Por lo tanto, cuando desarrollamos una clase, el ó los constructores deben de tener la capacidad de inicializar los aspectos básicos de funcionamiento del objeto.

En C#, cuando no implementamos ningún constructor, el compilador asume que tenemos un constructor sin parámetros, es decir, esto:

[more]

class MyClass
{
    public String Field1 { get; private set; }
    public String Field2 { get; private set; }
}

es lo mismo que esto:

class MyClass
{
    public String Field1 { get; private set; }
    public String Field2 { get; private set; }
 
    public MyClass()
    {
    }
}

En el momento que definamos un constructor con parámetros, el compilador deja de asumir la existencia del constructor sin ellos, el motivo me parece más que obvio, si definimos un constructor con parámetros estamos diciendo que nuestra clase necesita “otras cosas” para poder inicializarse correctamente; si queremos tener otro sin parámetros tendremos que definirlo explicitamente.

Una ve las ventajas de usar un constructor paramétrizado, es por ejemplo inicializar propiedades públicas con setter privado, y modificarlas desde el constructor en base a los parámetros (seguro que no lo has hecho nunca xD); pero la principal ventaja es que le dice al programador que se necesita para ser inicializado y poder empezar a trabajar. A veces no necesitamos parámetros y otras veces es inevitable y debemos definir un constructor sin parámetros, como por ejemplo para permitir la serialización en Xml.

Definir constructores es bastante llevadero y poco pesado, ya que gracias a la sobrecarga, se escriben rápido, sin repetir el código en cada uno de ellos y queda bastante claro:

class MyControl : Control
{
    public String Field1 { get; private set; }
    public String Field2 { get; private set; }
    public String Field3 { get; private set; }
 
    // base: nos permite pasar parámetros a la 
    // clase de la que heredamos
    public MyControl(Control parent, String text, String field1)
        : base(parent, text)
    {
        this.Field1 = field1;
    }
 
    // this: nos permite invocar a otro constructor
    // de la misma clase, de forma que lo que escribimos
    // en este prosigue la labor del otro, evitandonos escribir
    // otra vez lo mismo para cada constructor.
    public MyControl(Control parent, String text, String field1, String field2)
        : this(parent, text, field1)
    {
        this.Field2 = field2;
    }
 
    // this: nos permite llamar a cualquier constructor
    // de la misma clase.
    public MyControl(Control parent, String text, String field1, String field2, String field3)
        : this(parent, text, field1,field2)
    {
        this.Field3 = field3;
    }
}

También se pueden definir modificadores de acceso en los constructores, de forma que haya constructores que solo se puedan usar desde dentro de la misma clase(private), clase derivada(protected), ensamblado(internal) ó por todo el mundo(public). Útil para controlar desde donde se pueden instanciar nuestros objetos, ó cuantas veces, como en el patrón Singleton.

Además, podemos definir un constructor estático, sin parámetros, sin modificadores de acceso, imposible de invocar directamente… pero que nos permite inicializar lo que queramos antes que nigún miembro de la clase, estático ó de instancia, sea usado.

Bien, en C# 3.0 la inicialización rápida de objetos, permiten inicializar las propiedades públicas de una clase de una pasada:

class MyControl : Control
{
    public String Field1 { get;  set; }
    public String Field2 { get;  set; }
    public String Field3 { get;  set; }
    public String Field4 { get; private set; }
}
 
static void Main()
{
    MyControl mc = new MyControl() { Field1 = "f1", Field2 = "f2", Field3 = "f3" };
}

No voy a discutir de lo útil que es, porque definitivamente lo es, pero por supuesto no es una caracteristica para reemplazar los constructores porque:

  • No podemos inicializar campos privados ó propiedades públicas con setter privado.
  • Puede que necesitamos ejecutar alguna lógica ó incluso otros métodos en función del tipo de parámetros.
  • No denota cuales son las propiedades que necesita tener configuradas para poder considerarse totalmente inicializado, de cara a alguien que consuma nuestra clase a posteriori. Esto me parece lo más importante, ya que el código debe intentar ser autodescriptivo.

Al igual que los métodos parciales, métodos extensores ó tipos anónimos, es una nueva caracteristica para tener en cuenta y para usar cuando sea apropiado, no viene a reemplazar nada, viene a complementar para “esos casos” donde hace falta.

Si tu clase necesita datos ó ser inicializada, implementa un constructor parametrizado. Por la salud mental de nuestros compañeros de trabajo, hagamos un buen uso del lenguaje 😀

Constructores, inicializacion rapida de objetos y C# 3.0 | vtortola.NET

Asi da gusto usar Windows Vista

Pedazo de maquinón que estrené en el trabajo y con el que estoy más que contento, es un placer trabajar así.

image

Mi jefe es de esas personas que sabe como hacerte feliz. Después de algo más de una semana trabajando con él, cuando cojo mi portátil ya no es lo mismo… definitivamente tengo que hacerme con uno de estos para mi casa 😀

El monitor no es que se quede atrás:

image

Asi da gusto usar Windows Vista| vtortola.NET