Predicados y especificaciones

Inspirado en este post, decidí hacerme un ejemplito de predicados en .Net y así utilizar el patrón especificaciones.

Un predicado es un delegado que apunta a funciones que devuelven un valor booleano y aceptan un objeto genérico.

Vamos a ver una forma interesante de hacer filtrados en base a ciertos criterios de selección utilizando estos dichosos predicados de .Net.

Ciertamente podríamos implementar esto de la forma que siempre se hace, realizar un filtrado, iterando en una colección, y preguntando si tal elemento, se corresponde con el criterio elegido. Por ejemplo: recorrer la lista y vamos preguntando: este cliente…tiene correo gmail ?

Podría esbozarse un código como este:

 static public IList<Cliente> HasGmail(IList<Cliente> lista)
        {
            IList<Cliente> lista_resultado = new List<Cliente>();

            foreach(Cliente c in lista)
            {
                if(c.Email.Contains("@gmail.com"))
                {
                    lista_resultado.Add(c);
                }
            }
            return lista_resultado;
        }

Y se llamaría así:

IList<Cliente> usuariosDeGmail = ClienteFinder.HasGmail(lista);

Pero ahora bien, se podría objetizar el código, y hacerlo un poco más flexible, y hacer uso de predicados.

Podríamos reemplazarlos por esto:

IList<Cliente> usuariosDeGmail = 
                new ClienteFinder(lista).Find(EmailSpec.HasGmail);

Parecería estar más complicado, pero el concepto es sencillo y aplica el patrón de especificaciones, mediante predicatos genéricos.

Vamos al codigo de la entidad de negocio de la cual tenemos un listado y la queremos obtener por un criterio: la entidad Cliente.

public class Cliente
    {
        public Cliente()
        { }

        public Cliente(string nombre, string email)
        {
            this.nombre = nombre;
            this.email = email;
        }
        private string nombre;

        public string Nombre
        {
            get { return nombre; }
            set { nombre = value; }
        }

        private string email;

        public string Email
        {
            get { return email; }
            set { email = value; }
        }
    }

El código principal sería así:

 static void Main(string[] args)
        {
            CargarLista();

            //IList<Cliente> usuariosDeHotmail = new ClienteFinder(lista).Find(EmailSpec.HasHotmail);
            IList<Cliente> usuariosDeGmail = new ClienteFinder(lista).Find(EmailSpec.HasGmail);

            foreach (Cliente cliente in usuariosDeGmail)
            {
                Console.WriteLine("Email: {0}", cliente.Email);
            }

            Console.Read();
        }

Veamos el código de las especificaciones que se puede aplicar para obtener distintos criterios de filtrado:

public class EmailSpec
{
    public static Predicate<Cliente> HasHotmail
    {
        get{
            return delegate(Cliente cliente)
            {
                return cliente.Email.Contains("@hotmail.com");
            };

        }
    }

    public static Predicate<Cliente> HasGmail
    {
        get
        {
            return EmailSpec.MethodHasGmail;
        }
    }

    public static bool MethodHasGmail(Cliente cliente)
    {
        return cliente.Email.Contains("@gmail.com");
    }

    public static Predicate<Cliente> HasYahoo
    {
        get
        {
            return new Predicate<Cliente>(EmailSpec.MethodHasYahoo);
        }
    }

    public static bool MethodHasYahoo(Cliente cliente)
    {
        return cliente.Email.Contains("@yahoo.com");
    }

}

Aquí podemos ver, primeramente el uso de retorno de delegados usando Métodos anónimos (en HasHotmail), delegados con inferencia de tipos (en HasGmail) y la forma natural de usar un delegado (en HasYahoo). Estas son tres formas de hacer lo mismo, y yo recomiendo usar métodos anónimos que se vé en la propiedad HasHotmail y en este caso, el código se vuelve mucho más chico.

 public static Predicate<Cliente> HasHotmail
    {
        get{
            return delegate(Cliente cliente)
            {
                return cliente.Email.Contains("@hotmail.com");
            };

        }
    }

Vemos que la propiedad es de sólo lectura, y que también, retorna un predicado, que hablando mal, devolvería la función que se encargaría de la evaluación…y esa función…devolvería un booleano…true OR false, si cumple ó no. Muy prolijo no ? Sería lo mismo hacer:

  public static Predicate<Cliente> HasHotmail
    {
        get{
            return delegate(Cliente cliente)
            {
                if(cliente.Email.Contains("@hotmail.com"))
                    return true;
                else
                    return false;
            };

        }
    }

Ahora veamos el código de ClienteFinder:

public class ClienteFinder
{
    private IList<Cliente> _lista;

    public ClienteFinder(IList<Cliente> lista)
    {
        _lista = lista;
    }

    public IList<Cliente> Find(Predicate<Cliente> predicate)
    {
        List<Cliente> encontrados = new List<Cliente>();

        foreach (Cliente cliente in _lista)
        {
            if (predicate(cliente))
            {
                encontrados.Add(cliente);
            }
        }

        return encontrados;
    }

}

Lo importante acá es el constructor, que va a recibir la lista a ser filtrada. Y también el método Find, quien va a recibir el predicado correspondiente al criterio de selección. Es decir que Find puede recibir cualquiera de las tres especificaciones que preparamos: HasHotmail, HasGmail, HasYahoo, y realizar el filtrado en base a ellas.

Recursos:

Ahora… en WordPress

Si si…de ahora en adelante comenzaré a bloggear por aquí, por este canal llamado WordPress…lo que era Dario.Net (http://dariodotnet.blogspot.com) se ha convertido en este blog.

Seguiré hablando sobre programación, y tecnologías que sean interesantes comentarlas.

Saludos

Delegados, Eventos y Métodos anónimos

Introducción: Implementando una interfaz gráfica con windows forms, teniendo un MDI principal y un par de formularios hijos, vi la necesidad que en un momento dado, un formulario hijo realice algo que el padre tiene que interceptar, y tomar cartas en el asunto. En este caso necesitaba setear la propiedad Text del MDI, a partir de alguna acción de un formulario hijo; algo sencillo.

En C# y sin la posibilidad de usar algo análogo al namespace My, que posee la gente de VB.Net, tuve que recurrir a un Eventos y Delegados,…y ya que estamos…Métodos anónimos.

En VB.Net, estando en formulario hijo con el namespace my seria algo bastante tonto:

My.Forms.MDIMain.Text = nombredeltitulo

En C# me las arregle con un mecanismo que permita que el padre (MDI principal) se quede a la “escucha” de un evento, y así iniciar acciones, pero con información que le provee el hijo. Es decir:

  • Los metodos a ejecutar: son del MDI principal
  • Y la información necesaria -los parametros- : provienen del form hijo.

Ahora bien, como se podrían implementar estos tres conceptos juntos para resolver esto ?

Ahora pasemos a un ejemplo donde se vé una interacción entre los objetos:

using System;// Declaracion del delegado

public delegate void EventHandler(string str);

public class Program{

public static void Main()  {

TestHandler tb

= new TestHandler();

//Tres maneras de hacer lo mismo

//1- asignacion comun

        tb.Evento += new EventHandler(MetodoStringToUpper);

//2- asignacion por inferencia de tipos

        tb.Evento += MetodoStringToLower;

//3- asignacion con metodo anonimo

        tb.Evento += delegate(string str)                              {

string otrostring =   String.Format(

"Metodo Anonimo: {0}",str);                              Console.WriteLine(otrostring);

};

tb.Disparar();      Console.ReadLine();

}

public static void MetodoStringToUpper(string str)  {

Console.WriteLine(str.ToUpper());

}

public static void MetodoStringToLower(string str)  {

Console.WriteLine(str.ToLower());

}

}

class TestHandler{

//Evento de tipo EventHandler

    public event EventHandler Evento;

public void Disparar()  {

string mystring = "Dario.Net";

//Disparo el evento, con un string de parámetro

        Evento(mystring);  }

}

Primeramente declararemos un delegado: EventHandler, que podrá apuntar a metodos que contengan como argumentos el tipo string y que no retornen valores (void).

Luego en la clase TestHandler se declara un evento: Evento, del tipo EventHandler (nuestro delegado).

Y la funcion: Disparar(); se encargará de disparar el evento con un string como argumento: mystring=”Dario.Net”.

Vayamos al Main().

Instanciamos un objeto del tipo TestHandler, con el operador += y vamos agregando al evento, todos los métodos que queremos que se ejecuten, uno tras otro.

Luego invocamos a Disparar(). y se invocan, en este orden los tres métodos: MetodoStringToUpper,MetodoStringToLower y el querido metodo anónimo.

Cosas a notar:

El que dispara el evento es el TestHandler, y le pasa un parámetro: mystring.

Los métodos están en el Main, pero esos métodos se ejecutarán por el hijo…cosa loca no ?

El método anonimo: es como si fuera un metodo más, pero definido en el momento de su uso, e inline (buenísimo!)

Bien, ahora que vimos el ejemplo (y espero que lo hayan entendido), imaginemos algo: hagamos de cuenta que Program es el Main, y TestHandler es el Form1. Y podemos solucionar facilmente el problema que plantee al comienzo…y muchos más!

Para profundizar les recomiendo este artículo.

Saludos y dejen comentarios.

Developer Day

Ayer, 16 de agosto de 2006 se realizaron las jornadas de desarrollo en la UTN – Facultad Regional Resistencia – Chaco, donde se dieron lugar a interesantes charlas:

  • Web Semántica Por César Acuña
  • Programación en SQL Server 2000 y 2005Por Mariano Minoli
  • Lo Nuevo de Visual Basic 2005Por Vanina Geneiro y Diego Poza
  • Layering y ORM: Un caso realPor Dario Quintana
  • LINQPor Orlando Canteros y Guillermo Ruffino
  • Web ServicesPor Agustín Casiva y Marcos Ibañez

En dichas jornadas estuve compartiendo un tema: Desarrollo en capas y Object/Relational Mapping. Donde se mostró un aplicación real que implementaba estos patrones. La verdad, me gustó mucho dar la charla. Hasta después se mostró algo de db4o también, para poder ejemplificar mejor sobre diferencias entre bases de datos relacionales y orientadas a objetos.

Y despues Orlando y Guillermo hablaron sobre LINQ, la verdad que está demasiado bueno el tema…y no veo la hora que salga la versión final de este proyecto para empezar a usarlo en serio.

Reflexion + Generación de código = Modelo para AjGenesis

Estuve viendo AjGenesis, que es un generador de codigo escrito por Angel “Java” Lopez, la verdad muy útil. Se puede generar código para cualquier lenguaje que estén escritas las plantillas, y sino están escritas, las podés escribir con mucha facilidad, ya que vienen algunas plantillas de ejemplo como para ir conociendo el lenguaje AjGenesis. Para poder generar código se requiere, como todo generador de cógido: un modelo. Este modelo está escrito en XML.

Por ahora, AjGenesis, no cuenta con una interfaz amigable para un usuario final, pero funciona y genera de lo lindo. Para comenzar a usarlo se haría así:

#AjGenesis.Console.exe ModelsModel.xml Tasksgenerate.ajg
Donde Model.xml contiene los links a los otros archivos xml que contienen las descripciones de las entidades. Generate.ajg es el archivo de tareas que el generador vá a usar, vendría a ser como el archivo main para generar, él se encargará de buscar los templates. Por lo general el generate.ajg, tendrá un loop que iterará entre todas las entidades de negocio y así ir generando los artefactos en el lenguaje en que esten trabajando.

Ahora bien, como hago para obtener de forma automática el modelo?

En un proyecto que empecé con db4o, y el diseño de las business entities lo hacía con el Class Designer del Visual Studio 2005, se me ocurrió que el modelo de clases lo podía obtener del assembly donde están las clases de negocio. Es decir, tengo un proyecto que tiene adentro solo las clases de negocio, como podrían ser: Clientes, Factura, LineaFactura, etc.

Así nació GenerateFromAssembly, que es una herramienta muy sencilla, que via Reflexion, itera entre las clases de la dll, y obtiene sus propiedades con sus respectivos tipos de datos.

Actualmente la estoy usando en este proyecto, ya no con db4o, estoy usando NHibernate contra un Sql Server, pero la herramienta funciona igual, y genera el modelo como lo debe hacer.

Cabe destacar que la idea de la herramienta es: A partir del diseño de clases generar un assembly de .Net, y a partir de él, generar el modelo, y con el modelo y los templates de AjGenesis: obtengo mis artefactos, ya sean: Web Services, artefactos de capa de negocio, de capa de acceso a datos, o formularios web/windows.

Existe un issue: los tipos de datos genericos. Por ejemplo, si tengo IList<Cliente>, el CLR los trata como si fueran IList`[Cliente], es una cuestión de nombras, nada más. De modo que en el código final generado con AjGenesis obtendremos los tipos de datos con este último esquema. Se podría hacer otra herramienta, que al codigo final generado, lo masajee con algunas expresiones regulares y exprese los generic tipes segun el lenguaje .Net que estemos usando.

db4o: firsts steps

En estos días estuve teniendo mis primeros encontronazos de verdad con db4o, antes habian sido solo pruebas, estoy inscripto al foro hispano oficial, y estuve -para inaugurar- haciendo unas preguntas, que la verdad me sacaron un poco del pozo en el que estaba. Tambien conocí a gente como Alan Lavintman, que me estuvo dando una mano por chat con esta base. Obviamente, yo no podía pasar sin hacer la pregunta que el 90 % de los nuevos que comienzan a usar db4o, viniendo de usar un motor de datos relacional: “como manejo en la inserción la duplicidad de objetos?” ay!…esa pregunta es la del millon!

Este concepto es distinto, no es el mismo que el de un motor relacional, donde se puede manejar una entidad referencial por medio de claves. Por que en una dbms la inserción de los datos en una tabla intermedia -por ejemplo-, se podría implementar por medio de un INSERT INTO y listo, a lo sumo el motor se encargará de lanzar una excepción en el caso de que se viole una regla de integridad, pero no pasa de ahí. Con db4o es muuuuy distinto, creanme, y tiene sus “porques” bien justificados, y no porque db4o lo justifique, es que hablando de objetos…no podría ser de otra forma.

Vean esto, tengo dos clases, A y B, despues tengo una clase C (que vendría a ser si se quiere, como una “tabla intermedia”), en este caso seria un objeto que tiene relación con los otros dos objetos (A y B), en UML sería visto como una asociación como clase. Ahora, seamos un poco creativos, e imaginemos que tenemos que no tenemos la necesidad de guardar los objetos, por que nuestra memoria es no-volatil y no tengo problemas de capacidad de memoria (ni de velocidad si se quiere), de modo que tengo todos los objetos en memoria, y en vez de insertar, tengo que asociarlos nada más. Entonces tendré que tener en la mano el objeto del tipo C (es el nuevo objeto) y tambien los objetos del tipo A y B para asociarlos. De modo que podriamos ver que la clase de C tendría una propiedad de tipo A y otra propiedad de tipo B (minimamente), tambien podría tener otros atributos, por ejemplo Descripcion.

La clase C podría declararse así:


public class C { private A _A; private B _B; private string _Descripcion; public A A { get { return _A; } set { _A = value; } } public B B { get { return _B; } set { _B = value; } } public string Descripcion { get { return _Descripcion; } set { _Descripcion = value; } } }

Ahora tendriamos que setear las propiedades de C:

[...]

C ObjC = new C();

ObjC.A = objA;

ObjC.B = objB;

ObjC.Descripcion = "Esto es una descripcion";

[...]

…y así estariamos realizando la asociacion de dichos objetos.

Ahora olvidando el concepto de object prevalence (que hablando rapido es: tener todos los objetos en memoria -bien básico-) y volviendo a la realidad… volviendo a nuestra db4o, para tener que hacer una inserción de un objeto que tiene una asociacion con otros objetos, tenemos que:

1) Cargar primeramente los otros objetos.

2) Asociar los objetos, -seteando los campos del objeto a insertar-.

3) Guardar el nuevo objeto en la base.

4) Listo, objeto y las referencias ya se han realizado.

Otra cosa que me pareció interesante destacar, que a db4o le importa muy poco como sobreescribamos los metodos Equals, no realiza comparaciones con él.

Tambien puede ser de ayuda, el concepto de callbacks, que db4o implementa. Son funciones que se disparan cuando ocurren ciertos eventos.

Por ejemplo, está el callback ObjectCanNew que devuelve un bool, y se dispara cada vez que se está por insertar un nuevo objeto, si el resultado de la función devuelve true, se guarda el objeto, de lo contrario no. En esa función tendríamos que agregar el procedimiento de validación.

Pero este concepto intrusivo de db4object, particularmente no me gusta mucho, por que tenemos que decorar todas nuestras entidades de negocio con estos metodos.. que son parte del acceso a datos, y poco tiene que hacer en cuanto a una validación de negocios. Pero…es una opción.

Expresiones Regulares en .Net

Intentando desarrollar un parser, ya que veremos que parseamos 🙂 es imposible no caer en este tema de expresiones regulares, a menos de que nos fabriquemos una rutina que caracter a caracter vaya leyendo, almacenando en un buffer y comprobando si es lo que estamos buscando, podría ser una opción si es algo sencillo, pero…hgggssss.

O podemos ser los programadores duros y construirnos nuestra propia maquina de estados y con ella procesar las expresiones.Para los que no saben, o alguno que haya cursado conmigo Sintaxis y Semantica del Lenguaje y no se acuerda de los que nos hablaba el profe Bernal cuando nos hacía hacer la máquina de estados de una expresión regular dada, como aabbcc 😛 y ver como corrían las letras de un estado al otro, pero bueno…supongo que ese fue el lado oscuro de las Regex 😀
Una definición semi-formal: Una expresión regular es una cadena que describe o “matchea” a un conjunto de cadenas, dado un conjunto de reglas de sintaxis. En sintesis, es una cadena que representa a un patron que se busca en un texto. Un ejemplo más palpable, que por cierto los usamos a menudo, cuando queremos copiar archivos a un directorio: #cp *.cs /home/dario. Estamos aplicando el concepto. Esto en castellano seria como copiar todos los archivos (*) que tengan la extensión ‘cs’ a el directorio /home/dario. Es simple.

 

Las expresiones regulares funcionan de una manera similar. Tienen un conjunto finito de simbolos para la representación de caracteres, numeros, y como tambien simbolos para indicar cardinalidad.

Vayamos a un ejemplo: todos sabemos que una dirección IP se asemeja a: 10.66.43.141. Es decir, [numero 1-3 digitos][punto][numero 1-3 digitos][punto][numero 1-3 digitos][punto][numero 1-3 digitos]

Que mejor ejemplo para aplicar expresiones regulares. Aunque las diferencias se den, dependiendo del lenguaje que estamos trabajando, las expresiones regulares no varían mucho de una implementación a la otra. Por lo general todas las implementaciones se parecen bastante a la manera que lo hace Perl, cuyo motor de expresiones regulares es muy potente, mejor dicho, cuando te nombran Perl, lo primero que se me viene a la cabeza es RegEx, que ha tenido su inspiración en sed.Si programás en .Net y querés usar RegExs, The Regulator es ideal para armar las cadenas, probarlas y ver si funcionan como queremos, esta herramienta está hecha en .Net (dicho sea de paso).

Ejemplo: si queremos evaluar una expresión matemática para extraer sus operadores y operandos, y despues convertirla a postfija para su evaluación, primero debemos masajearla un poco.

Entonces, si tenemos una expresion como:

2.34m+344/444*(variable.value+33.55m+2^234)/2

La podríamos evaluar con la siguiente expresión regular, que usa el concepto de grupos, pero no es dificil de entender:

(?(?[d]+)u002e(?[d]+)m)|
(?d+)|
(?u0028|u0029|u002a|u002b|u002d|u002f|u005e)|
u0022(?.+)u0022|
(?[a-zA-Z0-9u002du002e]+)

donde:

  • \d –> representa un decimal.
  • [ ] –> uno, cualquiera de los caracteres dentro de los corchetes.
  • (? ) –> se utiliza para hacer grupos.
  • \u00xx –> representa un caracter unicode.
  • . –> cualquier caracter, excepto el retorno de carro.
  • | –> exclusión.
  • a-z –> cualquier caracter entre a y z.



Gmane y NHibernate-Hispano

Si sos un desarrollador de Software, profesional o más bien novaton (en este caso más aún) es casi imposible que no estes participando de al menos alguna lista de Correos, y si te interesan muchos temas lo más probable es que estés suscripto a varias.Hace tiempo que participo en listas de correos, más activas en algunas que otras, y en algunas solamente en modo “listen and learning” (mmm…no sé por qué me acorde de bridges). Por lo tanto, tener una herramienta que gestione los correos y que te facilite la lectura, es importante.

Bloggeando encontré hace ya hace un tiempo un mailing list archives, que basicamente es un archivador grandote que centraliza información de cientos (y me quedo corto…miles) de listas de correo en un lugar común.

Dos muy usados son Gmane y The Mail Archive.

NHibernate-Hispano, que como una bolita de nieve está creciendo de a poquito, me deja muy contento ya que el grupo se está poniendo bueno y muchos están conformes con las cositas que se están posteando. Porque de pronto no entontrabas un bendito ejemplo de NHibernate en la web, y ahora con el Grupo por lo menos entrás y recorrés la bandeja de entrada, encontrás ejemplos o soluciones que quizás te pueden servir, e inclusive, hay para todos lo gustos y colores.

Decidí, para probar, inscribir a nuestro fabuloso grupo en estos archivadores de listas de mail y estas son las direcciones:

La que más me gusta es Gmane, tiene inclusive un gráfico que te muestra la actividad del grupo en los pasados días.
Gmane, para registrar los tracks del grupo, se infiltra en el mismo como si fuera un miembro más. De modo que todos los mails que se manden al grupo, se manden tambien a Gmane para que él los archive.También Gmane te permite revisar tus mails en una vista tipo blog, es decir, te permite ver tu lista como si fuera un super-extenso blog que hasta si querés, podés cambiar el estilo modificando el CSS.

Y como todo: “Es cuestión de gustos”. Porque sino, podés usar Gmail y listo! (que es lo que uso). Lo que no me puedo imaginar es: alguien participando en más de 5 listas de correos muy activas y usando la bandeja de entrada de Yahoo ó Hotmail; la verdad que creo que no debe ser muy cómodo. En fin, creo que Gmail se presta muy bien para esto, y las felicitaciones son para él, pero los aplausos…para Ajax, la verdad este conjunto de tecnologías metidas en una sola, se lleva todos los premios, y como viene la mano…es lo que se viene.

Grupo de Usuarios de NHibernate en Español

Google Groups Es un Grupo de Usuarios de NHibernate en Español que está formandose, queremos sumar más gente e ir creciendo en experiencia con respecto a este Framework de Persistencia tan conocido, y con tan poca info en español.
Bueno, nos vemos ahí !!!

Correo electrónico:

Patron Proxy en C#

Este es un ejemplo del Patron Proxy adaptado x mí, lo traté de hacer lo suficientemente claro para que no requiera mucha explicación, pero…basicamente es:Empleado deriva de IPersona.
Defino los metodos de Empleado (que son los metodos reales)
Despues defino el Proxy que tambien deriva de IPersona, de modo que aun no estando instanciado realmente en memoria, puedo ocupar los metodos, de manera que retraso la instanciación (que es una de las motivaciones de este patron).
Cuando deseo ocupar los metodos de Empleado, no lo trato directamente con él, sino con su delegado, es decir, el Proxy.


//
// Ejemplo Utilizando el patron Proxy
//
using System;

namespace sampleProxy3
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
  IPersona obj = new Proxy();

  obj.PonerNombre("dario"); //este es el momento en que se crea
                             verdaderamente el objeto pero ya puedo
                             ocupar sus metodos.
  obj.Imprimir();
  Console.ReadLine();
}
}

public interface IPersona
{
string ObtenerNombre ();
void PonerNombre (string nombre);
void Imprimir();
}

public class Empleado : IPersona
{
string Nombre;
public Empleado(string nombre)
{
  this.Nombre = nombre;
}
public Empleado(){}
#region Miembros de IPersona

public string ObtenerNombre()
{
  return this.Nombre;
}

public void PonerNombre(string nombre)
{
  this.Nombre = nombre;
}
public void Imprimir()
{
  Console.WriteLine("El nombre es: "+this.Nombre);
}
#endregion
}

public class Proxy : IPersona
{
Empleado emp;
public void PonerNombre(string nombre)
{
  if (emp == null)
  {
      emp = new Empleado();
  }
  emp.PonerNombre(nombre);
}

public void Imprimir()
{
  if (emp == null)
  {
      emp = new Empleado();
  }
  emp.Imprimir();
}

public string ObtenerNombre()
{
  if (emp == null)
  {
      emp = new Empleado();

  }
  return emp.ObtenerNombre();
}

}
}

Un ejemplo de esto más tangible, es lo que hace el Visual Studio cuando se Agrega una Referencia Web -un Web Service-. Como vamos a necesitar ocupar los metodos del Web Service que lo tenemos en otra parte del mundo, primero te genera un proxy para que vos puedas interactuar con los metodos de las clases originales, sin interactuar con el objeto instanciado. De modo que el Intellisense nos deja ver todo lo que tiene para ofrecernos el Web Service.