Inicializadores de colecciones en C#

Días atrás hablaba de las formas de inicialización de objetos que nos proporcionaban las últimas versiones de C# y VB.Net, que permitían asignar valores a miembros de instancia de forma muy compacta, legible y cómoda.

C# 3.0 nos trae otra sorpresa, también relacionada con el establecimiento de valores iniciales de elementos: los inicializadores de colecciones. Aunque esta característica también estaba prevista para VB.Net 9.0, al final fue desplazada a futuras versiones por problemas de tiempo.

Para inicializar una colección, hasta ahora era necesario en primer lugar crear la clase correspondiente para, a continuación, realizar sucesivas invocaciones al método Add() con cada uno de los elementos a añadir:

 List<string> ls = new List<string>();
ls.Add(«Uno»);
ls.Add(«Dos»);
ls.Add(«Tres»);


C# 3.0 permite una alternativa mucho más elegante y rápida de codificar, simplemente se introducen los elementos a añadir a la colección entre llaves (como se hacía con los inicializadores de arrays o los nuevos inicializadores de objetos), separados por comas, como en el siguiente ejemplo:

 List<string> ls = 
new List<string>() { «Uno», «Dos», «Tres» };


Si desensamblamos el ejecutable resultante, podremos ver que es el compilador el que ha añadido por nosotros los Add() de cada uno de los elementos después de instanciar la colección:


newobj instance void class
[mscorlib]System.Collections.Generic.List`1<string>::.ctor()
stloc.s ‘<>g__initLocal0’
ldloc.s ‘<>g__initLocal0’
ldstr «Uno»
callvirt instance void class
[mscorlib]System.Collections.Generic.List`1<string>::Add(!0)
nop
ldloc.s ‘<>g__initLocal0’
ldstr «Dos»
callvirt instance void class
[mscorlib]System.Collections.Generic.List`1<string>::Add(!0)
nop
ldloc.s ‘<>g__initLocal0’
ldstr «Tres»
callvirt instance void class
[mscorlib]System.Collections.Generic.List`1<string>::Add(!0)
nop


Uniendo esto ahora con los inicializadores de objetos que ya tratamos un post anterior, fijaos en la potencia del resultado:

 List<Persona> lp = new List<Persona>
{
new Persona { Nombre=»Juan», Edad=34 },
new Persona { Nombre=»Luis», Edad=53 },
new Persona { Nombre=»José», Edad=23 }
};


Efectivamente, cada elemento es una nueva instancia de la clase Persona, con las propiedades que nos interesan inicializadas de forma directa. De hacerlo con los métodos tradicionales, para conseguir el mismo resultado deberíamos utilizar muuuchas más líneas de código.

Otro ejemplo que demuestra aún más la potencia de esta característica:

 var nums = new SortedList
{
{ 34, «Treinta y cuatro» },
{ 12, «Doce» },
{ 3, «Tres» }
};
foreach (var e in nums)
Console.WriteLine(e.Key + » » + e.Value);


En el código anterior podemos ver, primero, el uso de variables locales de tipo implícito, para ahorrarnos tener que escribir más de la cuenta. En segundo lugar, se muestra cómo se inicializa una colección cuyo método Add() requiere dos parámetros. En el caso de un SortedList<TKey, TValue>, su método Add() requiere la clave de ordenación y el valor del elemento.

(Obviamente, el resultado de la ejecución del código anterior será la lista ordenada por su valor numérico (Key))

En conclusión, se trata de otra de las innumerables ventajas que nos ofrece la nueva versión de C# destinadas a evitarnos pulsaciones innecesarias, y a la que seguro le daremos uso.

Publicado en: www.variablenotfound.com.

Chuleta de operadores estándar de consulta LINQ

Buscando información sobre los operadores estándar de consulta de Linq, me he topado en ASP.NET Resources con una chuleta (cheat sheet) que nos puede valer para tener siempre a mano una referencia rápida de los mismos, y de paso, adornar alguna pared que tengamos vacía ;-).

Puedes descargarla pulsando sobre la imagen:

Descargar archivo PDF

Si quieres leer más sobre estos operadores, puedes probar también en la referencia oficial, The .Net Standard Query Operators [ING], a leer este artículo traducido por el maestro Octavio Hernández, profundizar en MSDN, o en otros de los muchos sitios con información relacionada, como la referencia de Hooked On Linq [ING].

Publicado en: http://www.variablenotfound.com/.

Combinando ASP.NET MVC framework y jQuery, paso a paso

jQueryA la vista de la cantidad de posts que se están escribiendo al respecto y del entusiasmo que despierta su utilización, parece claro que jQuery se está erigiendo como un interesantísimo complemento para el framework MVC de Microsoft.

jQuery, para que el no haya oído hablar de ella, es una librería Javascript destinada a facilitar enormemente la vida a los desarrolladores simplificando y unificando el manejo de eventos, la manipulación del contenido (DOM), estilos, el uso de Ajax, la creación de animaciones y efectos gráficos, y un larguísimo etcétera propiciado por la facilidad para añadirle plugins que extienden sus funcionalidades iniciales. Y todo ello de forma muy rápida, sin excesivas complicaciones, y sin añadir demasiado peso a las páginas.

En este post vamos a ver un ejemplo de integración de jQuery con ASP.NET MVC framework realizando una aplicación muy sencilla e ilustrativa que nos enseñará cómo enviar información desde el cliente al servidor y actualizar porciones de página completas con el retorno de éste, respetando en todo momento la filosofía MVC.

El funcionamiento será realmente simple: el usuario introduce su nombre y edad, y al pulsar el botón se enviará esta información al servidor, que la utiliza para componer una respuesta y mandarla de vuelta al cliente. Cuando éste la recibe, la mostrará (con un poco de ‘magia’ visual de jQuery) y transcurridos unos segundos, desaparecerá de forma automática. La siguiente captura muestra el sistema que vamos a construir en ejecución:


MVC-jQuery en ejecución


Pero antes de entrar en faena, unos comentarios. En primer lugar, sólo voy a explicar los aspectos de interés para la realización del ejemplo, partiendo de las plantillas adaptadas para Web Developer Express 2008. Si prefieres antes una introducción sobre el framework, puedes visitar las magníficas traducciones de Thinking in .Net de los tutoriales de Scott Guthrië sobre MVC. Se refieren a la primera preview, pero los fundamentos son igualmente válidos.

Segundo, supongo que funcionará con versiones superiores de Visual Studio, pero no he podido comprobarlo. Está creado y comprobado con Visual Web Developer Express, y la Preview 2 del framework MVC.

Y por último, decir que el ejemplo completo podrás descargarlo usando el enlace que encontrarás al final del post. 🙂


Primero: Estructuramos la solución


En líneas generales, nuestra aplicación tendrá los siguientes componentes:



  • Tendremos un controlador principal, llamado Home. En él crearemos dos acciones, las dos únicas que permite nuestra aplicación: una, llamada Index, que se encargará de mostrar la página inicial del sistema, y otra llamada Welcome, que a partir de los datos introducidos por el usuario maquetará el interfaz del mensaje de saludo.

  • Como consecuencia del punto anterior, dispondremos de dos vistas. La primera, Index compondrá la interfaz principal con el formulario, y la segunda, que llamaremos Welcome, que define la interfaz del saludo al usuario (el recuadro de color amarillo chillón ;-)).

    Esta última vista necesitará los datos de la persona (nombre y edad) para poder mostrar correctamente su mensaje, por lo que el controlador deberá enviárselos después de obtenerlos de los parámetros de la petición.
    Fijaos que respetamos en todo momento el patrón MVC haciendo que el cliente invoque a la acción Welcome del controlador usando Ajax, y que la composición del interfaz (HTML) se realice a través de la vista correspondiente. Utilizaremos, por tanto, toda la infraestructura del framework MVC, sin modificaciones.

  • También, para añadir algo de emoción, he incluido una página maestra, que definirá el interfaz general de las páginas del sistema y realizará la inclusión de los archivos adicionales necesarios, como las hojas de estilo y scripts como jQuery.

Segundo: implementamos el controlador


El controlador de nuestra aplicación va a ser bien simple. Lo vemos y comentamos seguidamente:

public class HomeController : Controller
{
public void Index()
{
RenderView(«Index»);
}

public void Welcome(string name, int age)
{
Person person =
new Person { Age = age, Name = name };

RenderView(«Welcome», person);
}
}

public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}


Podemos observar la clase HomeController que implementa las acciones del controlador Home. La acción Index provoca la visualización de la vista de su mismo nombre.

La acción Welcome, es algo más compleja; en primer lugar, se observa que recibe dos parámetros, en nombre y edad del usuario, que utiliza para montar un objeto de tipo Person, definido algo más abajo, que posteriormente envía a la vista a la hora de renderizarla. Habréis observado aquí la utilización de inicializadores de objetos en la instanciación, y de propiedades automáticas en la definición del tipo.


Tercero: implementamos las vistas


Recordemos que vamos a implementar dos vistas, una para la página principal (llamada Index), que mostrará el formulario de entrada de datos, y otra (que llamaremos Welcome) que definirá el interfaz de la respuesta del servidor. Comenzaremos describiendo cómo incluir jQuery en nuestras páginas, y pasaremos después a ellas.


3.1. Inclusión de jQuery


Para implementar las vistas necesitamos antes preparar la infraestructura. En primer lugar, descargamos jQuery desde la web oficial del proyecto, y la introducimos en nuestro proyecto. Si vas a descargar la solución completa desde aquí, en ella ya viene incluido el archivo.

A continuación, es un buen momento para modificar la página maestra e incluir en ella la referencia a esta librería:

    <script  type=»text/javascript» 
src=»/scripts/jquery-1.2.3.min.js»>
</script>


Un inciso importante aquí. Hace unas semanas se publicó un HotFix para Visual Studio 2008 y Web Developer Express que corrije, entre otras, deficiencias en el intellisense y hacen posible el uso de esta magnífica ayuda cuando escribimos código jQuery. Altamente recomendable, pues, instalarse esta actualización.

Sin embargo, el hecho de introducir en la página maestra la referencia a la librería jQuery hace que el intellisense no funcione como debe. Por tanto, aunque no es la opción que he elegido en este proyecto, podríais incluir el script directamente en la vista Index en lugar de en la Master, y así disfrutaréis del soporte a la codificación.


3.2. La vista «Index»


Esta vista será la encargada de mostrar el formulario e implementar la lógica de cliente necesaria para obtener los datos del usuario, enviarlos al servidor y actualizar el interfaz con el retorno. Su implementación se encuentra en el archivo Index.aspx.

Desde el punto de vista del interfaz de usuario es bastante simple, lo justo para mostrar un par de inputs con sus correspondientes etiquetas y el botón que iniciará la fiesta llamando a la función send():

<form action=»» id=»myForm»>
<label for=»name»>Name: </label><input type=»text» id=»name» />
<br />
<label for=»age»>Age: </label><input type=»text» id=»age» size=»2″ />
<br />
<button id=»btn» onclick=»send(); return false;»>Send!</button>
</form>
<hr />
<div id=»result» style=»display: none; width: 400px»></div>


Observad que no es necesario establecer un action en el formulario, ni otros de los atributos habituales, pues éste no se enviará (de hecho, el formulario incluso sería innecesario). Fijaos también que el evento onclick del botón retorna false, para evitar que se produzca un postback (¡aaargh, palabra maldita! ;-)) del formulario completo.

Puede verse también un div llamado «result», inicialmente invisible, que se utilizará de contenedor para mostrar las respuestas obtenidas desde el servidor.

Pasemos ahora al script. La función send() invocada como consecuencia de la pulsación del botón pinta así:

   function send()
{
var name = document.getElementById(«name»).value;
var age = document.getElementById(«age»).value;
updateServerText(name, age);
}


En realidad no hace gran cosa: obtiene el valor de los textboxes y llama a la función que realmente hace el trabajo duro. Este hubiera sido un buen sitio para poner validadores, pero eso os lo dejo de deberes ;-).

El código de la función updateServerText() es el siguiente:

   function updateServerText(name, age)
{
document.getElementById(«btn»).disabled = true;

$.ajax({
cache: false,
url: ‘<%= Url.Action(«Welcome», «Home») %>’,
data: {
Name: name,
Age: age
},
success: function(msg) {
$(«#result»).html(msg).show(«slow»);
},
error: function(msg) {
$(«#result»).html(«Bad parameters!»).show(«slow»);
}
});

setTimeout(function () {
document.getElementById(«btn»).disabled = false;
$(«#result»).hide(«slow»);
}, 3000);
}


En primer lugar, se desactiva el botón de envío para evitar nuevas pulsaciones hasta que nos interese. He utilizado un método habitual del DOM, getElementById() para conseguirlo, no encontré una alternativa mejor en jQuery.

A continuación se utiliza el método ajax de jQuery para realizar la llamada al servidor. Aunque existen otras alternativas de más alto nivel y por tanto más fáciles de utilizar, elegí esta para tener más control sobre lo que envío, la forma de hacerlo y la respuesta.

Los parámetros utilizados en la llamada a $.ajax son:



  • cache, con el que forzamos la anulación de caché, obligando a que cada llamada se ejecute totalmente, sin utilizar el contenido almacenado en cliente. Internamente, jQuery añade al querystring un parámetro aleatorio, con lo que consigue que cada llamada sea única.

  • url, la dirección de invocación de la acción, que se genera utilizando el método de ayuda Url.Action(), pasándole como parámetros el controlador y la acción, lo que retornará la URL asociada en el sistema de rutas definido. En condiciones normales, si la aplicación se ejecuta sobre el raíz del servidor web, se traducirá por ‘/Home/Welcome’.

  • data, los datos a enviar, que se establecen en formato JSON, donde cada propiedad va seguida de su valor. jQuery tomará estos valores y los transformará en los parámetros que necesita la acción Welcome, por lo que el nombre de las propiedades deberá corresponder con los parámetros que espera esta acción (Name y Age).

  • sucess define la función de retorno exitoso, que mostrará los datos recibidos del servidor introduciéndolos en el contenedor «result». Y ya que estamos, gracias a la magia de jQuery, se mostrará con un efecto visual muy majo.

  • error, define una función de captura de errores para casos extraños, por si todo falla. Por ejemplo, dado que no estamos validando la entrada del usuario, si éste introduce texto en la edad, el framework no será capaz de realizar la conversión para pasarle los parámetros al controlador y fallará estrepitosamente; en este caso simplemente mostraremos un mensaje de error en cliente.


Fijaos que la llamada a la acción (Welcome) del controlador (Home) es capturada por el framework y dirigida al método correspondiente sin necesidad de hacer nada más, dado que se trata de una llamada HTTP normal. De hecho, si sobre el navegador se introduce la dirección «http://localhost:[tupuerto]/Home/Welcome?Name=Peter&Age=12» podremos ver en pantalla el mismo resultado que recibirá la llamada Ajax.



Obviamente, este efecto podría ser controlado y hacer que sólo se respondieran peticiones originadas a través de Ajax y similares.

Por último, continando con el código anterior, dejamos programado un timer para que unos segundos más tarde, el mensaje mostrado, sea cual sea el resultado de la llamada Ajax, desaparezca lentamente y, de paso, se active de nuevo el botón de envío. El efecto, ya lo veréis si ejecutáis la solución, es de lo más vistoso, creando una sensación de interactividad y dinamismo muy a lo 2.0 que está tan de moda.


3.3. La vista «Welcome»


En esta vista definiremos el interfaz del mensaje que mostraremos al usuario cuando introduzca su información y pulse el botón de envío. Dado que estamos usando MVC, la llamada Ajax descrita anteriormente llegará al controlador y éste hará que la vista cree el interfaz que será devuelto al cliente.

La vista, por tanto, es como cualquier otra, salvo algunas diferencias interesantes. Por ejemplo, no tiene página maestra, no la necesita; de hecho ni siquiera tiene la estructura de una página HTML completa, sólo de la porción que necesita para montar su representación. El código de Welcome.aspx, salvo las obligatorias directivas iniciales, es:

<div style=»background-color: Yellow; border: 1px solid black;»>
<em>Message from server (<%=DateTime.Now %>):</em><br />
Hi, <%= ViewData.Name %>, your age is <%= ViewData.Age %>
</div>


Pero aún queda un detalle que afinar. En el archivo code-behind (o codefile) donde se define la clase Welcome hay que indicar expresamente que la clase es una vista de un tipo concreto de la siguiente forma:

  public partial class Views_WebParts_Welcome : ViewPage<Person>
{
}


De esta forma indicamos que los datos de la vista son del tipo Person, lo que nos permite beneficiarnos del tipado fuerte en la composición de la misma; de hecho, esto es lo que permite que podamos usar tan alegremente una expresión como ViewData.Age a la hora de componer el interfaz.

Fijaos que aunque en este ejemplo no hemos hecho ninguna composición compleja y los datos que hemos usado, contenidos en ViewData, han sido obtenidos por el Controlador directamente de la vista, sería exactamente igual si se tratara de algo menos simple, como una página concreta de datos obtenidos desde el Modelo, por ejemplo con Linq, y mostrados en forma de grid.


Cuarto: recapitulamos


Hemos visto, paso a paso, un ejemplo de cómo podemos utilizar el framework MVC de Microsoft para el desarrollo de aplicaciones web que hacen uso de Ajax, utilizando para ello la excelente librería de scripting jQuery.

Para ello hemos creado una vista que es la página Web con el formulario principal, y otra vista parcial con el fragmento compuesto por el servidor con la información recibida. El controlador, por su parte, incluye acciones para responder a las peticiones del cliente independientemente de si se originan a través de Ajax o mediante la navegación del usuario, mostrando la vista oportuna.

La modificación dinámica del interfaz, así como las llamadas asíncronas al servidor, encajan perfectamente en la filosofía MVC teniendo en cuenta algunas reglas básicas, como el respeto a las responsabilidades de cada capa.

Y ahora, lo prometido:

   Descargar el proyecto Descargar proyecto (Visual Web Developer Express 2008).

Publicado en: www.variablenotfound.com.

Efectos laterales en métodos parciales

¡Sorpresa!Hace unos días comentaba que el uso de métodos parciales puede causar algunos problemas en la ejecución de nuestras aplicaciones que podríamos calificar, cuanto menos, de «incómodos».

Recordemos que una parte de una clase parcial puede declarar un método y utilizarlo (invocarlo) dentro de su código; si el método está implementado en otro fragmento de la clase, se ejecutará como siempre, pero si no ha sido implementado, el compilador eliminará tanto la declaración del método como las llamadas que se hagan al mismo.

Sin embargo esta eliminación pueden causar efectos no deseados difíciles de detectar.

Veámoslo con un ejemplo. Supongamos una clase parcial como la siguiente, que representa a una variable de tipo entero que puede ser incrementada o decrementada a través de métodos:

 public partial class Variable
{
partial void Log(string msg);
private int i = 0;

public void Inc()
{
i++;
Log(«Incremento. I: » + i);
}

public void Dec()
{
Log(«Decremento. I: » + (–i));
}

public int Value
{
get { return i; }
}
}


Creamos ahora un código que utiliza esta clase de forma muy simple: crea una variable, la incrementa dos veces, la decrementa una vez y muestra el resultado:

 Variable v = new Variable();
v.Inc();
v.Inc();
v.Dec();
Console.WriteLine(v.Value);


Obviamente, tras la ejecución de este código la pantalla mostrará por consola un «1», ¿no? Claro, el resultado de realizar dos incrementos y un decremento sobre el cero.

Pues no necesariamente. De hecho, es imposible conocer, a la vista del código mostrado hasta ahora, cuál será el resultado mostrado por consola al finalizar la ejecución. Dependiendo de la existencia de la implementación del método parcial Log(), declarado e invocado en la clase Variable anterior, puede ocurrir:



  • Si existe otra porción de la misma clase (otra partial class Variable) donde se implemente el método, se ejecutará éste. El valor mostrado por consola, salvo que desde esta implementación se modificara el valor del campo privado, sería «1».


  • Si no existe una implementación del método Log() en la clase, el compilador eliminará todas las llamadas al mismo. Pero si observáis, esto incluye el decremento del valor interno, que estaba en el interior de la llamada como un autodecremento:
    Log(«Decremento. I: » + (–i));
    Por tanto, en este caso, el compilador eliminará tanto la llamada a Log() como la operación que se realiza en el interior. Obviamente, el resultado de ejecución de la prueba anterior sería «2».

    Lo mismo ocurriría si el resultado a mostrar fuera el valor de retorno de una llamada a otra función: esta no se ejecutaría, lo cual puede ser grave si en ella se realiza una operación importante, como por ejemplo:
    public function InicializaValores()
    {
    Log(«Elementos reestablecidos: » + reseteaElementos() );
    }
     

Conclusión: usad los métodos parciales siempre con precaución, pues podemos introducir errores muy difíciles de detectar y corregir, sobre todo por falta aparente de relación entre causa y efecto.

Por ejemplo, imaginad que el ejemplo anterior contiene una implementación de Log(); la aplicación funcionaría correctamente. Sin embargo, si pasado un tiempo se decide eliminar esta implementación (por ejemplo, porque ya no es necesario registrar las operaciones realizadas), la operación de decremento (Dec()) dejaría de funcionar.

Aunque, eso sí, no es nada que no se pueda solucionar con un buen juego de pruebas…

Publicado en: http://www.variablenotfound.com/.

Métodos parciales en C# 3 y VB.NET 9

Piezas de puzzleUna vez visto el concepto de las clases parciales, ya es posible profundizar en los métodos parciales, una característica aparecida en las nuevas versiones de los lenguajes estrella de Microsoft, C# y VB.Net.

Estos métodos, declarados en el contexto de una clase parcial, permiten comunicar de forma segura los distintos fragmentos de dicha clase. De forma similar a los eventos, permiten que un código incluya una llamada a una función que puede (o no) haber sido implementada por un código cliente, aunque en este caso obligatoriamente la implementación se encontrará en uno de los fragmentos de la misma clase desde donde se realiza la llamada.

En la práctica significa que una clase parcial puede declarar un método y utilizarlo (invocarlo) dentro de su código; si el método está implementado en otro fragmento de la clase, se ejecutará como siempre, pero si no ha sido implementado, el código correspondiente a la llamada será eliminado en tiempo compilación para optimizar el resultado… ¡sí, eliminado!

Por ejemplo, el siguiente código muestra una declaración de un método parcial en el interior de una clase, y su utilización desde dentro de uno de sus métodos:

 // C#
public partial class Ejemplo
{

// El método parcial se declara
// sin implementación…

partial void Log(string msg);


public void RealizarAlgo()
{
hacerAlgoComplejo();
Log(«¡Ojo!»); // Usamos el método
// parcial declarado antes

}

[…] // Otros métodos y propiedades

}

‘ VB.NET
Partial Public Class Ejemplo

‘ El método parcial se declara, sin
‘ implementar nada en el cuerpo

Partial Private Sub Log(ByVal msg As String)
End Sub


Public Sub RealizarAlgo()
HacerAlgoComplejo()
Log(«¡Ojo!») ‘ Usamos el método parcial
End Sub

[…] ‘ Otros métodos y propiedades
End Class


Y esta la parte realmente curiosa. Cuando el compilador detecta la invocación del método parcial Log(), buscará en todos los fragmentos de la clase a ver si existe una implementación del mismo. Si no existe, eliminará del ensamblado resultante la llamada a dichos métodos, es decir, actuará como si éstas no existieran en el código fuente.

En caso afirmativo, es decir, si existen implementaciones como las del siguiente ejemplo, todo se ejecutará conforme a lo previsto:

 // C#
public partial class Variable
{
partial void Log(string msg)
{
Console.WriteLine(msg);
}
}

‘ VB.Net
Partial Public Class Variable
Private Sub Log(ByVal msg As String)
Console.WriteLine(msg)
End Sub
End Class


Antes comentaba que los métodos parciales son, en cierto sentido, similares a los eventos, pues conceptualmente permiten lo mismo: pasar el control a un código cliente en un momento dado, en el caso de que éste exista. De hecho, hay muchos desarrolladores que lo consideran como un sustituto ligero a los eventos, pues permite prácticamente lo mismo pero se implementan de forma más sencilla.

Existen, sin embargo, algunas diferencias entre ambos modelos, como:



  • Los métodos parciales se implementan en la propia clase, mientras que los eventos pueden ser consumidos también desde cualquier otra
  • El enlace, o la suscripción, a eventos es dinámica, se realiza en tiempo de ejecución, es necesario incluir código para ello; los métodos parciales, sin embargo, se vinculan en tiempo de compilación
  • Los eventos permiten múltiples suscripciones, es decir, asociarles más de un código cliente
  • Los eventos pueden presentar cualquier visibilidad (pública, privada…), mientras que los métodos parciales son obligatoriamente privados.

También puede verse como algo parecido a la herencia en una jerarquía de clases. Una clase puede incluir un método virtual vacío y utilizarlo en su implementación, y si una clase hija sobreescribe el mismo, ésta se ejecutará en su lugar. Pero claro, hay que tener en cuenta que el ámbito de consumo del método parcial es la misma clase donde se declara e implementa.

Por último, es conveniente citar algunas consideraciones sobre los métodos parciales:



  • Deben ser siempre privados (ya lo había comentado antes)
  • No deben devolver valores (en VB.Net serían SUB, en C# serían de tipo void)
  • Pueden ser estáticos (shared en VB)
  • Pueden usar parámetros, acceder a los miembros privados de la clase… en definitiva, actuar como un método más de la misma


En resumen, los métodos parciales forman parte del conjunto de novedades de C# y VB.Net que no son absolutamente necesarias y que a veces pueden parecer incluso diabólicas, pues facilitan la dispersión de código y dificultan la legibilidad. Además, en breve publicaré un post comentando posibles efectos laterales a tener en cuenta cuando usemos los métodos parciales en nuestros desarrollos.

Sin embargo, es innegable que los métodos parciales nos facilitan enormemente la inclusión de código de usuario en el interior de clases generadas de forma automática. Por ejemplo, el diseñador visual del modelo de datos de LinqToSQL genera los DataContext como clases parciales, en las que define un método parcial llamado OnCreated(). Si el usuario quiere incluir alguna inicialización personal al crear los DataContext, no tendrá que tocar el código generado de forma automática; simplemente creará otro fragmento de la clase parcial e implementará este método, de una forma mucho más natural y cómoda que si se tratara de un evento.

Publicado en: http://www.variablenotfound.com/.

Ocultar el texto de validadores en javascript (ASP.Net)

Pablo ha lanzado una pregunta en el post Deshabilitar y habilitar un validador ASP.Net desde Javascript publicado hace unos meses, que creo interesante responder en una entrada en exclusiva, por si puede ayudar a alguien más.

«Al utilizar la funcion ValidatorEnable para habilitar un validador, me activa automaticamente la validacion, y me muestra el texto que pongo para cuando la validacion no se cumpla, como puedo evitar esto»


Recordemos que el post trataba sobre cómo conseguir, desde Javascript, habilitar o deshabilitar validadores de controles incluidos en un webform utilizando la función ValidatorEnable(), que pone a nuestra disposición ASP.Net.

El problema, como comenta Pablo, es que al habilitar la validación desde script se muestran de forma automática los mensajes de error en todos aquellos controles que no sean válidos, provocando un efecto que puede resultar desconcertante para el usuario.

Indagando un poco, he comprobado que el problema se debe a que ValidatorEnable(), después de habilitar el validator, comprueba si los valores del control son correctos, mostrando el error en caso contrario.

Existen al menos dos formas de solucionar este problema.

La primera consiste en jugar con la visibilidad del mensaje de error. Como se observa en el siguiente código, al llamar a la función HabilitaValidador(), ésta llamará a ValidatorEnable y acto seguido, si el control no es válido, oculta el mensaje de error:


function HabilitaValidador(validator, habilitar)
{
ValidatorEnable(validator, habilitar);
if (habilitar && !validator.isvalid)
validator.style.visibility = «hidden»;
}

La segunda forma consiste en simular el comportamiento interno de ValidatorEnable, pero eliminando la llamada a la comprobación de la validez del control.

    function HabilitaValidador(validator, habilitar)
{
validator.enabled = habilitar;
}

Como se puede ver, simplemente se está estableciendo la propiedad enabled del validador, sin realizar ninguna comprobación posterior.

En ambos casos, la forma de utilizar esta función desde script sería la misma:


function activar()
{
HabilitaValidador(«<%= RequiredFieldValidator1.ClientID %>», true);
}

Para mi gusto la opción más limpia, aunque sea jugando con la visibilidad de los elementos, es la primera de las mostradas, pues se respeta el ciclo completo de validación. En el segundo método nos estamos saltando las validaciones y el seguimiento de la validez global de la página, que la función original ValidatorEnable sí contempla.

Espero que esto resuelva la duda.

Publicado en: www.variablenotfound.com.

Otras 101 citas célebres del mundo de la informática

Semanas atrás publicaba el post «101 citas célebres del mundo de la informática«, la traducción del post original de Timm Martin en Devtopics, «101 Great computer quotes«. El tema me pareció tan divertivo e interesante que he realizado una nueva recopilación de otras tantas frases relacionadas con el mundo de la informática, y con especial énfasis en el desarrollo de software.


Informática


1. «No temo a los ordenadores; lo que temo es quedarme sin ellos»
     — Isaac Asimov

2. «Una vez un ordenador me venció jugando al ajedrez, pero no me opuso resistencia cuando pasamos al kick boxing»
     — Emo Philips

3. «La informática tiene que ver con los ordenadores lo mismo que la astronomía con los telescopios»
     — Edsger W. Dijkstra

4. «El ordenador nació para resolver problemas que antes no existían»
     — Bill Gates

5. «El software es como la entropía: difícil de atrapar, no pesa, y cumple la Segunda Ley de la Termodinámica, es decir, tiende a incrementarse»
     — Norman Augustine

6. «El software es un gas: se expande hasta llenar su contenedor»
     — Nathan Myhrvold

7. «Todas las piezas deben unirse sin ser forzadas. Debe recordar que los componentes que está reensamblando fueron desmontados por usted, por lo que si no puede unirlos debe existir una razón. Pero sobre todo, no use un martillo»
     — Manual de mantenimiento de IBM, año 1925

8. «Los estándares son siempre obsoletos. Eso es lo que los hace estándares»
     — Alan Bennett

9. «La física es el sistema operativo del Universo»
     — Steven R Garman

10. «El hardware es lo que hace a una máquina rápida; el software es lo que hace que una máquina rápida se vuelva lenta»
     — Craig Bruce


Conocimiento


11. «La imaginación es más importante que el conocimiento. El conocimiento es limitado, mientras que la imaginación no»
     — Albert Einstein

12. «El mayor enemigo del conocimiento no es la ignorancia, sino la ilusión del conocimiento»
     — Stephen Hawking

13. «Cuanto más sabes, más te das cuenta de que no sabes nada»
     — Sócrates

14. «Dime y lo olvido, enséñame y lo recuerdo, involúcrame y lo aprendo»
     — Benjamín Franklin

15. «El auténtico conocimiento es conocer la extensión de la propia ignorancia»
     — Confucio

16. «Si la gente no hiciera cosas estúpidas, nunca se podría haber hecho nada inteligente»
     — Ludwig Wittgenstein

17. «Obtener información de internet es como intentar beber agua de una boca de incendios»
     — Mitchell Kapor


Usuarios


18. «Si piensas que los usuarios de tus programas son idiotas, sólo los idiotas usarán tus programas»
     — Linus Torvalds

19. «Desde el punto de vista de un programador, el usuario no es más que un periférico que teclea cuando se le envía una petición de lectura»
     — P. Williams

20. «¿Dónde está la tecla ‘ANY’?»
     — Homer Simpson, frente a un mensaje «press any key»

21. «Los ordenadores son buenos siguiendo instrucciones, no leyendo tu mente»
     — Donald Knuth

22. «Sólo hay un problema con el sentido común: que no es demasiado común»
     — Milt Bryce

23. «Tus clientes más descontentos son tu mayor fuente de aprendizaje»
     — Bill Gates

24. «Tenemos que cambiar la tradicional actitud ante la construcción de software. En vez de pensar que nuestra principal tarea es indicar a un ordenador qué hacer, concentrémonos en explicar a las personas lo que queremos que el ordenador haga»
     — Donald E. Knuth


Internet


25. «¿Internet? No estamos interesados en eso»
     — Bill Gates

26. «La mejor forma de obtener información correcta de los foros de Usenet es enviar algo incorrecto y esperar las correcciones»
     — Matthew Austern


Profesionales


27. «La mayoría de expertos está de acuerdo en que la causa más probable de destrucción del mundo sería por accidente; y aquí es donde entramos nosotros: somos profesionales de la informática, causamos accidentes»
     — Nathaniel Borenstein

28. «Dicen que los pesimistas ven el vaso medio vacío; los optimistas, en cambio, lo ven medio lleno. Los ingenieros, por supuesto, ven que el vaso es el doble de grande de lo que sería necesario»
     — Bob Lewis

29. «Si en una sala llena de diseñadores de software dos de ellos están de acuerdo, eso es una mayoría»
     — Bill Curtis

30. «Es importante destacar que ningún ingeniero software con ética consentiría escribir un procedimiento llamado DestruirBaghdad. Su ética le obligaría a escribir un procedimiento DestruirCiudad, al que se pasaría el parámetro Baghdad»
     — Nathaniel S. Borenstein

31. «Una de las cosas más fascinantes de los programadores es que no puedes saber si están trabajando o no sólo con mirarlos. A menudo están sentados aparentemente tomando café, chismorreando o mirando a las nubes. Sin embargo, es posible que estén poniendo en orden todas las ideas individuales y sin relación que pululan por su mente»
     — Charles M. Strauss

32. «Si piensas que vales lo que sabes, estás muy equivocado. Tus conocimientos de hoy no tienen mucho valor más allá de un par de años. Lo que vales es lo que puedes llegar a aprender, la facilidad con la que te adaptas a los cambios que esta profesión nos regala tan frecuentemente»
     — José M. Aguilar, en cómo tu blog te ayuda a encontrar empleo


Programación


33. «Los programas deben ser escritos para que los lean las personas, y sólo incidentalmente, para que lo ejecuten las máquinas»
     — Abelson and Sussman

34. «Comentar el código es como limpiar el cuarto de baño; nadie quiere hacerlo, pero el resultado es siempre una experiencia más agradable para uno mismo y sus invitados»
     — Ryan Campbell

35. «Tenemos que dejar de optimizar para programadores y comenzar a optimizar para usuarios»
     — Jeff Atwood

36. «La programación en bajo nivel es buena para el alma del programador»
     — John Carmack

37. «Está bien investigar y resolver misteriosos asesinatos, pero no deberías necesitar hacerlo con el código. Simplemente deberías poder leerlo»
     — Steve McConnell

38. «Si queremos contar líneas de código, no deberíamos referirnos a ellas como líneas producidas, sino como líneas consumidas»
     — Edsger Dijkstra

39. «La programación puede ser divertida, al igual que la criptografía; sin embargo, ambas no deberían combinarse»
     — Kreitzberg and Shneiderman

40. «Antes de que un software sea reutilizable debería ser utilizable»
     — Ralph Johnson

41. «Si automatizas un procedimiento desastroso, obtienes un procedimiento desastroso automatizado»
     — Rod Michael

42. «Ley de Alzheimer de la programación: si lees un código que escribiste hace más de dos semanas es como si lo vieras por primera vez»
     — Via Dan Hurvitz

43. «Es más fácil cambiar las especificaciones para que encajen con el software que hacerlo al revés»
     — Alan Perlis

44. «Menos del 10% del código tienen que ver directamente con el propósito del sistema; el resto tiene que ver con la entrada y salida, validación de datos, mantenimiento de estructuras de datos y otras labores domésticas»
     — Mary Shaw

45. «Si tienes una función o procedimiento con diez parámetros, probablemente hayas olvidado uno»
     — Alan Perlis

46. «Es raro que mantener el código de otro desarrollador sea como entrar en un edificio de gran diseño que admiras mientras paseas por él y planeas cómo añadirle un ala o algún elemento decorativo. Lo más frecuente es que sea como tirarse de cabeza a un gran montón de basura maloliente»
     — Bill Venners

47. «La generación de código, como beber alcohol, es bueno si se hace con moderación»
     — Alex Lowe


Desarrollo


48. «La simplicidad llevada al extremo se convierte en elegancia»
     — Jon Franklin

49. «Un programa nunca está completo por debajo del 90% ni por encima del 95%»
     — Terry Baker

50. «Cuando estás en un atasco de tráfico con un Porsche, todo lo que puedes hacer es consumir más combustible que el resto estando parado. La escalabilidad va de construir carreteras más anchas, no coches más rápidos»
     — Steve Swartz

51. «Todo el mundo sabe el peligro de la optimización prematura. Pienso que deberíamos estar igualmente preocupados con el diseño prematuro, es decir, el hecho de diseñar demasiado pronto lo que un programa debería hacer»
     — Paul Graham

52. «Programar sin una arquitectura o diseño en mente es como explorar una gruta sólo con una linterna: no sabes dónde estás, dónde has estado ni hacia dónde vas»
     — Danny Thorpe

53. «La mejor forma de predecir el futuro es implementarlo»
     — David Heinemeier Hansson

54. «Lo realmente necesario es saberlo todo sobre los cambios en la información. Nadie quiere o necesita que le recuerden 16 horas al día que tiene sus zapatos puestos»
     — David Hubel

55. «En dos ocasiones me han preguntado: ‘si pone datos incorrectos en la máquina, ¿saldrán las respuestas correctas?’. Soy absolutamente incapaz de hacerme una idea del tipo de confusión de ideas que pueden provocar que alguien haga una pregunta así»
     — Charles Babbage

56. «Hazlo todo tan simple como sea posible, pero no más simple»
     — Albert Einstein

57. «Hoy en día la mayoría del software existe no para resolver un problema, sino para actuar de interfaz con otro software»
     — I. O. Angell

58. «Unas buenas especificaciones incrementará la productividad del programador mucho más de lo que puede hacerlo cualquier herramienta o técnica»
     — Milt Bryce

59. «La diferencia entre la teoría y la práctica es que, en teoría, no hay diferencia entre la teoría y la práctica»
     — Richard Moore, desarrollador de KDE


Errores y depuración


60. «No documentes el problema; arréglalo»
     — Atli Björgvin Oddsson

61. «Por norma, los sistemas software no funcionan bien hasta que han sido utilizados y han fallado repetidamente en entornos reales»
     — Dave Parnas

62. «Si el código y los comentarios no coinciden, posiblemente ambos sean erróneos»
     — Norm Schryer

63. «Creo que es una nueva característica. No le cuentes a nadie que fue un accidente»
     — Larry Wall

64. «Si no las capturas y procesas, cerramos tu aplicación. Esto incrementa enormemente la fiabilidad de tu sistema»
     — Anders Hejlsberg, sobre las excepciones en .Net

65. «Cuando se está depurando, el programador novato introduce código correctivo; el experto elimina el código defectuoso»
     — Richard Pattis

66. «En un proyecto software con diez personas, probablemente tres de ellas introducen tantos errores que podríamos considerar su productividad como negativa»
     — Gordon Schulmeyer

67. «Es inevitable que la gente programe mal, y la formación no mejorará sustancialmente las cosas. Tenemos que aprender a vivir con ello»
     — Alan Perlis

68. «El testing de componentes puede ser muy efectivo para mostrar la presencia de errores, pero absolutamente inadecuado para demostrar su ausencia»
     — Edsger Dijkstra


Lenguajes y tecnologías


69. «La gestión manual de bloques de memoria en C es como hacer malabarismos con pastillas de jabón en la ducha de la prisión: todo diversión hasta que cometes un fallo»
     — Un usuario anónimo de un foro Usenet

70. «No pueden existir concursos de Perl ofuscado; no tendría sentido»
     — Jeff Polk (Nota: ¡sí que los hay!)

71. «Java es lo más penoso que le ha ocurrido a la informática desde MS-DOS»
     — Alan Kay

72. «Sólo hay dos cosas malas en C++: el concepto inicial y la implementación»
     — Bertrand Meyer

73. «Era una broma, ¿vale? Si hubiéramos pensado que iba a usarse no la habríamos escrito»
     — Mark Andreesen, hablando de la etiqueta BLINK de HTML

74. «Los Servicios Web son como el sexo entre los adolescentes. Todos hablan de hacerlo, pero aquellos que realmente lo hacen, lo hacen muy mal»
     — Michelle Bustamante

75. «Perl: el único lenguaje cuyo código es prácticamente igual antes y después de someterlo a una encriptación RSA»
     — Keith Bostic

76. «No trabajé duro para hacer Ruby perfecto para todo el mundo, porque todos somos diferentes. Intenté hacer Ruby perfecto para mí, así que puede que a tí no te lo parezca; probablemente, el mejor lenguaje para Guido van Rossum es Python»
     — Yukihiro Matsumoto, aka «Matz», creador de Ruby

77. «XML no es más lenguaje de programación que unas notas sobre una servilleta de papel»
     — Charles Simonyi

78. «BASIC es a la programación lo que QWERTY a la mecanografía»
     — Seymour Papert

79. «Se ha descubierto que C++ dispone de una gran facilidad para ocultar los detalles triviales de un programa… así como dónde están sus bugs»
     — David Keppel

80. «UNIX es simple. Sólo necesita un genio para entender su simplicidad»
     — Dennis Ritchie

81. «Algunos desarrolladores cuando se enfrentan a un problema piensan que la solución es usar expresiones regulares. En este momento, ya tienen dos problemas»
     — Jamie Zawinski


Seguridad


82. «Pienso que los virus informáticos muestran la naturaleza humana: la única forma de vida que hemos creado hasta el momento es puramente destructiva»
     — Stephen Hawking

83. «El único sistema seguro es aquél que está apagado en el interior de un bloque de hormigón protegido en una habitación sellada rodeada por guardias armados»
     — Gene Spafford

84. «Saber romper medidas de seguridad no hacen que seas hacker, al igual que saber hacer un puente en un coche no te convierte en un ingeniero de automoción»
     — Eric Raymond

85. «Las organizaciones gastan millones de dólares en firewalls y dispositivos de seguridad, pero tiran el dinero porque ninguna de estas medidas cubre el eslabón más débil de la cadena de seguridad: la gente que usa y administra los ordenadores»
     — Kevin Mitnick

86. «Si piensas que la tecnología puede solucionar tus problemas de seguridad, está claro que ni entiendes los problemas ni entiendes la tecnología»
     — Bruce Schneier

87. «Los bulos (hoaxes) que circulan por internet usan la debilidad del ser humano para asegurar su replicación y distribución. En otras palabras, utilizan los resquicios del Sistema Operativo Humano»
     — Stewart Kirkpatrick

88. «Las contraseñas son como la ropa interor. No puedes dejar que nadie la vea, debes cambiarla regularmente y no debes compartirla con extraños»
     — Chris Pirillo


Empresa


89. «En realidad no trato de destruir a Microsoft: eso será sólo un efecto colateral no intencionado»
     — Linus Torvalds

90. «Sí, tenemos unas reglas de vestuario en la empresa. Tienes que vestirte»
     — Scott McNealy, co-fundador de Sun Microsystems

91. «En el mundo del software, los activos más importantes de la compañía se van a casa todas las noches. Si no se les trata bien, pueden no volver al día siguiente»
     — Peter Chang

92. «Es mejor esperar a que un desarrollador productivo esté disponible que esperar a que el primer desarrollador disponible sea productivo»
     — Steve C McConnell

93. «No soy de los que piensan que Bill Gates es el diablo. Simplemente sospecho que si Microsoft alguna vez se encontrara con el diablo, no necesitarían un intérprete»
     — Nicholas Petreley


Predicciones


94. “En dos años el problema del spam se habrá resuelto”
     — Bill Gates, 2004

95. «El problema de los virus es pasajero. En un par de años estará resuelto»
     — John McAfee, 1988

96. “Los virus informáticos son una leyenda urbana”
     — Peter Norton, 1988

97. «En 2031, los abogados serán componentes habituales de la mayoría de los equipos de desarrollo»
     — Grady Booch

98. “No sé cómo será el lenguaje del año 2000, pero sé que se llamará Fortran”
     — C. A. Hoare, 1982

99. «En el futuro es posible que los ordenadores no pesen más de 1,5 toneladas»
     — Popular mechanics, 1949

100. “Veo poco potencial comercial en Internet, al menos durante diez años”
     — Bill Gates, 1994

101. «Antes de que el hombre alcance la luna, el correo será enviado en unas horas desde Nueva York a California, Inglaterra, India o Australia con misiles guiados. Estamos en la era del misil-correo»
     — Arthur Summerfield, 1959, Correos de los Estados Unidos





Publicado originalmente en: Variable not found
Más citas, la primera entrega en:
101 citas célebres del mundo de la informática

Clases parciales en C# y VB.NET

Piezas de puzzleAunque las clases parciales aparecieron hace unos años, con la llegada de .Net 2.0 y Visual Studio 2005, vamos a hacer un breve repaso como preparación para un próximo post que trate los métodos parciales.

Las clases parciales (llamados también tipos parciales) son una característica presente en algunos lenguajes de programación, como C# y VB.Net, que permiten que la declaración de una clase se realice en varios archivos de código fuente, rompiendo así la tradicional regla «una clase, un archivo». Será tarea del compilador tomar las porciones de los distintos archivos y fundirlas en una única entidad.

En VB.Net y C#, a diferencia de otros lenguajes, es necesario indicar explícitamente que una clase es parcial, es decir, que es posible que haya otros archivos donde se continúe la declaración de la misma, usando en ambos con la palabra clave partial en la definición del tipo:

  ‘ VB.NET 
Public Partial Class Persona

End Class

// C#
public partial class Persona
{

}

En este código hemos visto cómo se declara una clase parcial en ambos lenguajes, que es prácticamente idéntica salvo por los detalles sintácticos obvios. Por ello, a partir de este momento continuaré introduciendo los ejemplos sólo en C#.

Pero antes un inciso: la única diferencia entre ambos, estrictamente hablando, es que C# obliga a que todas las apariciones de la clase estén marcadas como parciales, mientras que en VB.Net puede dejarse una de ellas (llamémosla «declaración principal») sin indicar que es parcial, y especificarlo en el resto de apariciones. En mi opinión, esta no es una práctica recomendable, por lo que aconsejaría utilizar el modificador partial siempre que la clase lo sea, e independientemente del lenguaje utilizado, pues contribuirá a la mantenibilidad del código.

El número de partes en las que se divide una clase es indiferente, el compilador tomará todas ellas y generará en el ensamblado como si fuera una clase normal.

Para comprobarlo he creado un pequeño código con dos clases exactamente iguales, salvo en su nombre. Una de ellas se denomina PersonaTotal, y está definida como siempre, en un único archivo; la otra, PersonaParcial, es parcial y la he troceado en tres archivos, como sigue:

  // *** Archivo PersonaParcial.Propiedades.cs ***
// Aquí definiremos todas las propiedades

partial class PersonaParcial
{
public string Nombre { get; set; }
public string Apellidos { get; set; }
}

// *** Archivo PersonaParcial.IEnumerable.cs ***
// Aquí implementaremos el interfaz IEnumerable

partial class PersonaParcial: IEnumerable
{
public IEnumerator GetEnumerator()
{
throw new NotImplementedException();
}
}

// *** Archivo PersonaParcial.Metodos.cs ***
// Aquí implementaremos los métodos que necesitemos

partial class PersonaParcial
{
public override string ToString()
{
return Nombre + » » + Apellidos;
}
}

Y efectivamente, el resultado de compilar ambas clases, según se puede observar con ILDASM es idéntico:

Clases generadas tras la compilación
A la hora de crear clases parciales es conveniente tener los siguientes aspectos en cuenta:



  • Los atributos de la clase resultante serán la combinación de los atributos definidos en cada una de las partes.
  • El tipo base de los distintos fragmentos debe ser el mismo, o aparecer sólo en una de las declaraciones parciales.
  • Si se trata de una clase genérica, los parámetros deben coincidir en todas las partes.
  • Los interfaces que implemente la clase resultante será la unión de todos los implementados por las distintas secciones.
  • De la misma forma, los miembros (métodos, propiedades, campos…) de la clase final será la unión de todos los definidos en las distintas partes.

Vale, ya hemos visto qué son y cómo se usan, pero, ¿para qué sirven? ¿cuándo es conveniente utilizarlas? Pues bien, son varios los motivos de su existencia, algunos discutibles y otros realmente interesantes.

En primer lugar, no era sencillo que varios desarrolladores trabajaran sobre una misma clase de forma concurrente. Incluso utilizando sistemas de control de versiones (como Sourcesafe o Subversion), la unidad mínima de trabajo es el archivo de código fuente, y la edición simultánea podía generar problemas a la hora de realizar fusiones de las porciones modificadas por cada usuario.

En segundo lugar, permite que clases realmente extensas puedan ser troceadas para facilitar su comprensión y mantenimiento. Igualmente, puede utilizarse para separar código en base a distintos criterios:



  • por ejemplo, separar la interfaz (los miembros visibles desde el exterior de la clase) y por otra los miembros privados a la misma
  • o bien separar las porciones que implementan interfaces, o sobreescriben miembros de clases antecesoras de los pertenecientes a la propia clase
  • o separar temas concernientes a distintos dominios o aspectos

En tercer lugar, aunque da la impresión que fue el motivo más importante para decidir su inclusión, las clases parciales permiten utilizar de forma efectiva herramientas automáticas de generación de código.

Así, es posible que un desarrollador y un generador estén introduciendo cambios sobre la misma clase sin molestarse, cada uno jugando con su propia porción de la clase; el primero puede introducir funcionalidades sin preocuparse de que una nueva generación automática de código pueda machacar su trabajo. Visual Studio y otros entornos de desarrollo hacen uso intensivo de esta capacidad, por ejemplo, en los diseñadores visuales de Windows Forms, WPF, ASP.Net e incluso el generador de modelos de LinqToSql.

Publicado en: http://www.variablenotfound.com/.