Leandro.... me hiciste laburar.... :))) Bueno le dedique un rato al problema, no es que el tema me encanta...., y arme esto.
El uso seria asi, mira como se vería la clase:
using System;
using System.Collections.Generic;
using System.Text;
using AlgoDeAtributos00;
namespace AlgoDeAtributos
{
public class AlgunaClase
{
private string[] propiedad;
private string[] otraPropiedad;
[LazyAttribute(typeof(ProviderA) )]
public string[] Propiedad
{
get {
propiedad=(string[])LazyFactoryHelper.InvokeLoad(propiedad);
return propiedad;
}
set { propiedad = value; }
}
[LazyAttribute(typeof(ProviderB))]
public string[] OtraPropiedad
{
get
{
otraPropiedad =
(string[])LazyFactoryHelper.InvokeLoad(otraPropiedad);
return otraPropiedad;
}
set { otraPropiedad = value; }
}
public AlgunaClase(){ }
}
}
Antes de avanzar una aclaración, ahora el Lazy funciona como Lazy!!!!!!!!!
Si la propiedad es null se carga, si es distinta de null se respeta el valor
y no se toca.!!!!!
Veamos el Helper: :)))
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Reflection;
namespace AlgoDeAtributos00
{
public static class LazyFactoryHelper
{
public static object InvokeLoad(object destination)
{
if (destination == null) *// Aca se determina si hay que hacer
la carga o no!!!!!!!*
{
StackTrace st = new StackTrace(false);
MethodBase mb = st.GetFrame(1).GetMethod();
if (mb.IsSpecialName) *// Esto sirve para determinar si el
llamador es una propiedad o un metodo !!!!
* if (mb.Name.IndexOf("get_", 1, 1,
StringComparison.OrdinalIgnoreCase)!=0)* // Verifica que sea el get de la
propiedad !!!!*
{
PropertyInfo pi = mb.DeclaringType.GetProperty(
mb.Name.Substring(4));* // Obtiene el PropertyInfo del invacador !!!!*
foreach (LazyAttribute o in
pi.GetCustomAttributes(typeof(LazyAttribute),
false))
{
*destination = (o.GetProvider() as
Provider).GetItems(2); // Aqui se invoca la carga desde el provider obtenido
por la factory!!!!!
* }
}
}
return destination;
}
}
}
Bue, te adjunto el ejemplo completo.
Espero te guste y se ajuste a tu necesidad. Los tipos retornados dependen de
lo que vos declares en tus providers, yo use string[] pero hubiera podido
usar cualquier cosa.
La contra de este método, va son dos como minimos, 1 *acoplamiento*, 2 Se
explora el stacktrace y no es lo mas performante....
Lo bueno de este metodo, :) , es *desacoplado*. ( en definitiva estamos
haciendo una forma de IoC )
La magia de Net....
Saludos
Daniel Calvin
PD: Contame si te gusto.....
El día 16/11/07, Daniel Calvin <[EMAIL PROTECTED]> escribió:
>
> Hola Lenadro
>
> Ese codigo se puede evitar.
> Hay que construir un helper que lo implemente.
>
> Si lo haces con un helper dentro de la propiedad deberías incluir la linea
> que invoque al helper.
> Menos de eso no se puede.
> Si queres hacerlo en forma transparente, sin meter codigo dentro de la
> propiedad, hay que hacer un poco mas de magia.
> En ese caso la entidad la deberias instanciar desde una factory, ese
> factory te retornaría una instancia de un proxy generado al vuelo para esa
> entidad, el se encargaria de implementar el lazy en base al atributo.
>
> Si tengo un rato te escribo el código del helper con un lazy load real,
> eso que escribi no es lazy load, fue solo una muestra de como invocar una
> factory en base a un attibute.
>
> Te estoy mareando?.....
>
> Bue trato de hacerte un ejemplito mas serio.
>
> Saludos
>
> Daniel Calvin
>
> El día 16/11/07, Leandro Tuttini < [EMAIL PROTECTED]> escribió:
> >
> >
> > Daniel, la verdad te pasaste muy buen codigo.
> >
> > Se que puede llegar a ser muy complejo, pero como evitaria ingresar este
> > codigo:
> >
> > System.Reflection.PropertyInfo pi =this.GetType
> > ().GetProperty("Propiedad");
> > foreach (LazyAtribute o in
> > pi.GetCustomAttributes(typeof(LazyAtribute),
> > false))
> > {
> > propiedad=(o.GetProvider() as Provider).GetItems(2);
> > }
> >
> > en la entidad, y colocarlo dentro del atributo.
> > O es justo esta parte la que mencionabas realizarla con dinamic proxy.
> >
> > Como decia la intriga que tengo es como acceder a propiedad (o su
> > variable privada) de la entidad desde dentro del atributo.
> > Si es que esto se puede.
> >
> > Pero esta muy bueno el codigo, esta bueno como define que provider
> > utilizar.
> >
> > Gracias
> >
> >
> > *Daniel Calvin < [EMAIL PROTECTED]>* escribió:
> >
> > Hola Leandro
> >
> > No es muy lindo lo que vas a hacer, pero te doy una punta.
> > Podes usar StackTrace para que el nombre de la propiedad que invoca al
> > atributo sea dinamica, incluso podrias extraer parte del codigo y meterlo en
> > un helper.
> >
> > El secreto esta en este pedacito:
> > System.Reflection.PropertyInfo pi =this.GetType
> > ().GetProperty("Propiedad");
> > foreach (LazyAtribute o in
> > pi.GetCustomAttributes(typeof(LazyAtribute),
> > false))
> > {
> > propiedad=(o.GetProvider() as Provider).GetItems(2);
> > }
> > Es bastante mejorable si te pones.
> >
> > Tenes que tener en cuenta que es muy acoplado, pero, funciona. :))
> >
> > Te adjunto un rar con la solucion completa, no se si no la filtrara el
> > mug.
> > Por las dudas te pego todo el código aca abajo.
> >
> > Saludos
> >
> > Daniel Calvin
> > PD: Yo usaria proxies dinámicos.... :))
> >
> >
> > Tu clase sera algo asi si mal no entendi:
> > using System;
> > using System.Collections.Generic;
> > using System.Text;
> > using AlgoDeAtributos00;
> > namespace AlgoDeAtributos
> > {
> > public class AlgunaClase
> > {
> > private string[] propiedad;
> >
> > [LazyAtribute(typeof(ProviderA))]
> > public string[] Propiedad
> > {
> > get {
> > System.Reflection.PropertyInfo pi =this.GetType
> > ().GetProperty("Propiedad");
> > foreach (LazyAtribute o in
> > pi.GetCustomAttributes(typeof(LazyAtribute),
> > false))
> > {
> > propiedad=(o.GetProvider() as Provider).GetItems(2);
> > }
> > return propiedad;
> > }
> > set { propiedad = value; }
> > }
> > [LazyAtribute(typeof(ProviderB))]
> > public string[] OtraPropiedad
> > {
> > get
> > {
> > System.Reflection.PropertyInfo pi =
> > this.GetType().GetProperty("OtraPropiedad");
> >
> > foreach (LazyAtribute o in
> > pi.GetCustomAttributes(typeof(LazyAtribute),
> > false))
> > {
> > propiedad = (o.GetProvider() as
> > Provider).GetItems(2);
> > }
> > return propiedad;
> > }
> > set { propiedad = value; }
> > }
> > public AlgunaClase(){ }
> > }
> > }
> >
> >
> > Bueno el programita de prueba seria algo asi:
> > using System;
> > using System.Collections.Generic;
> > using System.Text;
> > namespace AlgoDeAtributos
> > {
> > class Program
> > {
> > static void Main(string[] args)
> > {
> > AlgunaClase ac = new AlgunaClase();
> > foreach (string s in ac.Propiedad)
> > Console.WriteLine(s);
> > foreach (string s in ac.OtraPropiedad)
> > Console.WriteLine(s);
> > }
> > }
> > }
> > La salida producida algo parecido a esto:
> > Item uno
> > Item dos
> > Item unoPrima
> > Item dosPrima
> >
> > Tu atributo LazyAttributte es algo asi:
> > using System;
> > using System.Collections.Generic;
> > using System.Text;
> > namespace AlgoDeAtributos00
> > {
> > public class LazyAtribute:Attribute
> > {
> > private Provider provider =null;
> > public LazyAtribute(Type factoryType)
> > {
> > this.provider = factoryType.InvokeMember("",
> > System.Reflection.BindingFlags.CreateInstance, null, this.provider,
> > null) as Provider;
> > }
> > public Provider GetProvider() { return provider; }
> > }
> > }
> > Tus providers para que el ejemplo funcione serian:
> >
> > using System;
> > using System.Collections.Generic;
> > using System.Text;
> > namespace AlgoDeAtributos00
> > {
> > public abstract class Provider
> > {
> > public abstract string[] GetItems(int family);
> >
> > }
> > public class ProviderA:Provider
> > {
> > public ProviderA() { }
> > public override string[] GetItems(int family) { return new
> > string[] { "Item uno", "Item dos" }; }
> > }
> > public class ProviderB : Provider
> > {
> > public ProviderB() { }
> > public override string[] GetItems(int family) { return new
> > string[] { "Item unoPrima", "Item dosPrima" }; }
> > }
> > }
> >
> >
> >
> > El día 15/11/07, Leandro Tuttini <[EMAIL PROTECTED]>
> > escribió:
> > >
> > > Muchas gracias a todos por las respuestas.
> > >
> > > Les comento, la idea es hacer en un principio algo simple, la entidad
> > > deberia poder utilizar los atributos y a este indicarle que Factory de
> > > provider utilizar o es el especializado para cargar la propiedad.
> > > Se que con esto queda medio acoplada la entidad pero seria la primer
> > > version de prueba.
> > >
> > > En el final de seguro sera algo con dinamic proxy o algo asi, de
> > > seguro al estilo que se utiliza en Castle project,
> > > http://www.castleproject.org/dynamicproxy/index.html
> > >
> > > Si tienen ejemplos seran de mucha ayuda, que muestre como un atributo
> > > se ejecute antes de la propiedad y que permita setear el valor de esta.
> > > Cualquier ejemplo que vean pueden aportar sera de ayuda, y que por
> > > supuesto puedan compartir.
> > > Lo que no me termina de cerrar es como desde un atributo poder acceder
> > > a la variable de la propiedad, para asignarle un valor.
> > >
> > > Diego muy bueno el ejemplo de codeproject, aunque por lo que vi
> > > utiliza una libreria PostSharp, creo que el secreto esta en esta.
> > >
> > > Bueno voy a seguir analizando el tema.
> > > Saludos
> > > **
> > > ------------------------------
> > >
> > > Los referentes más importantes en compra/venta de autos se juntaron:
> > > Demotores y Yahoo!. Ahora comprar o vender tu auto es más fácil.
> > > Visitá http://ar.autos.yahoo.com/
> > >
> >
> >
> >
> > --
> > Daniel A. Calvin
> > Cooperator Team Member
> > http://www.cooperator.com.ar
> > Microsoft Certified Professional
> >
> >
> > ------------------------------
> >
> > Los referentes más importantes en compra/venta de autos se juntaron:
> > Demotores y Yahoo!. Ahora comprar o vender tu auto es más fácil.
> > Visitá http://ar.autos.yahoo.com/
> >
> >
>
>
> --
> Daniel A. Calvin
> Cooperator Team Member
> http://www.cooperator.com.ar
> Microsoft Certified Professional
>
--
Daniel A. Calvin
Cooperator Team Member
http://www.cooperator.com.ar
Microsoft Certified Professional
AlgoDeAtributos.rar
Description: Binary data
