Desafio V - Retornando tipos anônimos

by Fujiy 13. janeiro 2010 08:41

Os tipos anônimos introduzidos no C# 3.0 para facilitar o uso do LINQ agilizam o desenvolvimento, evitando que tenhamos que declarar uma classe em casos específicos.

Mas esses tipos tem alguma limitações, intencionais, por exemplo, não podemos usar os tipos gerados como retorno ou parâmetro de um método. Até porque os tipos gerados são internal.

O desafio é retornar um tipo anônimo e usá-lo no seu código, sem usar Reflection. Não tem uso prático, já que não é uma boa prática fazer isso, mas serve como exercício.

 

Para adiantar, vou postar o método que faz o retorno:

public static object RetornaAnonimo()
{
return new {Id = 1, Nome = "João"};
}

 

Agora resta conseguir usar o tipo numa chamada. Ex.:

var retorno = RetornaAnonimo();

....

 

Tags:

Artigos

Desafio IV - Sobrecarga de métodos

by Fujiy 24. setembro 2009 23:10

Considerando o seguinte código, qual será o resultado?

class Program
{
      static void Main()
      {
           Derived c = new Derived();
           c.Metodo(1);
      }
}

public class Base
{
      public void Metodo(int a)
      {
           Console.WriteLine("Int32 / " + a.GetType());
      }
}

public class Derived:Base
{
      public void Metodo(object a)
      {
          Console.WriteLine("Object / " + a.GetType());
      }
}

Tags:

Artigos

Desafio III - Membros Static

by Fujiy 14. agosto 2009 11:24

As seguintes classes geram o mesmo resultado? Se não, por quê?

public class A
{
     public static string X = "A";
}

public class A
{
     public static string X;

     static A()
     {
          X = "A";
     }
}


Teoricamente deveriam ser iguais, mas a segunda classe é equivalente à:

public class A
{
     public static string X = "A";

     static A()
     {
     }
}

A diferença está existência ou não do construtor. Quando não há construtor a classe é marcada como beforefieldinit, fazendo com que o type initializer seja chamado antes mesmo de qualquer referência à algum membro da classe.

Podemos perceber isso com o seguinte código:

class Program
{
     static void Main(string[] args)
     {
          Console.WriteLine("Iniciando");
          A.Escrever("Escrever");
          Console.WriteLine("Depois de escrever");
          string y = A.X;
          Console.WriteLine("Depois de acessar o campo X");

          Console.ReadKey();
     }
}

public class A
{
     public static string X = Escrever("X (Type Initializer)");

     public static string Escrever(string s)
     {
          Console.WriteLine(s);
          return s;
     }
}

Antes de qualquer coisa, o tipo já é inicializado. Mas se você criar um construtor, mesmo que vazio, a ordem das chamadas vai mudar.

O Type Initializer só é executado antes da primeira referência ao tipo. No caso antes do A.Escrever("Escrever").

Curioso, e pode gerar um comportamento inesperado.

Tags:

Artigos

Curiosidade no Math.Round do .Net

by Fujiy 7. julho 2009 09:03

Sempre pensei que um número no formato *.5  arredondava para cima, mas na verdade arredonda pro número par mais próximo. Por exemplo:

Console.WriteLine(Math.Round(4.4)); // 4
Console.WriteLine(Math.Round(4.5)); // 4
Console.WriteLine(Math.Round(4.6)); // 5
Console.WriteLine(Math.Round(5.5)); // 6

Este tipo de método se chama Banker's rounding

 

Tags: ,

Artigos

Desafio II - Trocando valores

by Fujiy 1. julho 2009 14:53

Sendo:

int i1 = valorx;
int i2 = valory;

Como trocar os valores das variaveis sem criar outra variavel temporária?

A resposta está nos comentários.

Tags:

Artigos

Associando entidades por ID no Entity Framework

by Fujiy 17. junho 2009 14:33

Uma dica que pode ajudar muito:

Imagine que temos um relacionamento da tabela Mensagem com a Usuario, normalmente fariamos o seguinte para criar um relacionamento:

Mensagem mens = new Mensagem();
mens.Usuario = from us in contexto.UsuarioSet
where us.Id = 10
select us;

contexto.AddToMensagemSet(mens);
contexto.SaveChanges();

O problema é fazemos uma consulta no banco somente para criar o relacionamento, sendo que já temos a informação necessária para isso, o Id do Usuario.
Existe uma outra forma de fazer isso sem consultar o banco de dados:

Mensagem mens = new Mensagem();
mens.UsuarioReference.EntityKey = new EntityKey("YourEntitiesModel.UsuarioSet", "Id", 10);

contexto.AddToMensagemSet(mens);
contexto.SaveChanges();

Assim economizamos um Select, o que faz a diferença quando temos muitas chamadas

Tags:

Artigos

ASP.NET MVC no IIS 6.0

by Fujiy 9. fevereiro 2009 07:25

Agora com a versão Release Candidate do ASP.NET MVC resolvi começar a estudar sobre o assunto.

Como ainda sou usuário e fã do Windows XP, já imaginei que poderia ter problemas com o IIS 6.0. Acontece que o IIS só passa pro ASP.NET as chamadas que estão configuradas para isso, usando a extensão do arquivo. Então quando você chama a página /Home/About o ASP.NET nem fica sabendo, o IIS logo fala que a página não existe.

Você tem duas opções pra resolver o problema. Uma é adicionar um redirecionamento pro ASP.NET usando o wildcard *, isso faz com que todas as chamadas sejam enviados pro ASP.NET, o que terá impacto no desempenho geral do seu site.

A outra opção, que considero melhor, apesar de alterar sua URL é usar a extensão .aspx nas URLs, /Home/About será /Home.aspx/About. Além de não impactar no desempenho, na maioria das vezes é sua única opção pra quem usa hospedagem compartilhada e não tem acesso ao servidor.

Como o ASP.NET MVC cria os links quando você usa o Html.ActionLink, a única alteração necessária é no Global.asax, onde você vai apagar a rota padrão, e adicionar as seguinte:

routes.MapRoute(
"Default",
"{controller}.aspx/{action}/{id}",
new { action = "Index", id = "" }
);

routes.MapRoute(
"Root",
"",
new { controller = "Home", action = "Index", id = "" }
);

A segunda é apenas para o diretório raiz funcionar.

Depois de mudar o Global.asax basta compilar e atualizar o servidor que já vai funcionar!

Tags: , ,

Artigos

Executando script após update via AJAX

by Fujiy 6. fevereiro 2009 14:14

Uma dica pra quem quiser executar um script sempre após o update do Ajax no Asp.Net.
Alguem scripts não funcionam se você envia-los pelo ScriptManager, pois precisam ser executados após a requisição do Ajax ser terminada e fechada. É o caso do PNGFix pro Internet Explorer 6.0.
Se você carregar imagens no seu UpdatePanel, o PNGFix não funciona pras novas imagens, mesmo mandando executar novamente pelo ScriptManager, esta foi a única alternativa que encontrei.

É simples, adicione a seguinte chamado ao body:

<body onload=" RegisterEndRequest()">

E adicione o script na sua página:

function RegisterEndRequest() {

Sys.WebForms.PageRequestManager.getInstance().add_endRequest(EndRequestHandler);

}

function EndRequestHandler() {

$('.imagem').pngFix();

}

A primeira função é a que será chamada pelo onload do body, ela vai registrar a outra função para que seja executada sempre que terminar um update do Ajax. Na EndRequestHandler você coloca o seu código.

Simples!

Tags: ,

Artigos

Desafio I - Dynamic Iterators

by Fujiy 16. julho 2008 11:46

Vou propor um desafio: Qual o resultado do seguinte código? E por quê?

    public class MainClass
    {
        static bool DeveMudar = false;
 
        public static void Main()
        {
            Console.WriteLine(DeveMudar);
            MetodoQualquer();
            Console.WriteLine(DeveMudar);
            Console.ReadKey();
        }
 
        public static IEnumerable<int> MetodoQualquer()
        {
            DeveMudar = true;
            yield return 1;
        }
    }

Tags:

Artigos

Design Patterns (Padrões de Projeto de Software) II: Observer

by Fujiy 14. julho 2008 22:01

Continuando a série de artigos sobre Design Patterns, vamos discutir o Observer.

Vou novamente recorrer a definição da Wikipedia:

Define uma dependência um-para-muitos entre objetos de modo que quando um objeto muda o estado, todos seus dependentes sejam notificados e atualizados automaticamente. Isto é o padrão Observer e permite que objetos interessados sejam avisados da mudança de estado ou outros eventos ocorrendo num outro objeto.

O padrão Observer é também chamado de Publisher-Subscriber, Event Generator, Dependents.



O Observer é composto de duas partes, o Subject que é o objeto que muda de estado com uma frequência imprevisível e os Observers que devem pedir que sejam notificados das mudanças de estado do Subject.

Os Observers podem se "cadastrar" e "descadastrar" para receber essas notificações.

Veja um diagrama do pattern:

E vamos partir para os códigos:

ISubject.cs:

 

    public interface ISubject
    {
        void Registrar(IObserver observador);
 
        void Desregistrar(IObserver observador);
 
        void Notificar();
    }

IObserver.cs

    public interface IObserver
    {
        void Atualizar();
    }

SubjectConcreto.cs:

        private string _SubjectState = "ON";
 
        public string SubjectState
        {
            get
            {
                return _SubjectState;
            }
            set
            {
                _SubjectState = value;
            }
        }
 
        private List<IObserver> Observers = new List<IObserver>();
 
        #region ISubject Members
 
        public void Registrar(IObserver observador)
        {
            Observers.Add(observador);
        }
 
        public void Desregistrar(IObserver observador)
        {
            Observers.Remove(observador);
        }
 
        public void Notificar()
        {
            foreach (IObserver Observador in Observers)
            {
                Observador.Atualizar();
            }
        }
 
        #endregion
    }

ObserverConcreto.cs:

    public class ObserverConcreto : IObserver
    {
        private string _Nome;
        private string _ObserverState;
        private SubjectConcreto _Subject;
 
        public SubjectConcreto Subject
        {
            get { return _Subject; }
            set { _Subject = value; }
        }
 
        public ObserverConcreto(SubjectConcreto pSubject, string pNome)
        {
            this._Subject = pSubject;
            this._Nome = pNome;
        }
 
        #region IObserver Members
 
        public void Atualizar()
        {
            _ObserverState = _Subject.SubjectState;
            Console.WriteLine("Novo estado do Observer {0} é {1}", _Nome, _ObserverState);
        }
 
        #endregion
    }

Agora que temos nossas classes, vamos testa-las:

        static void Main(string[] args)
        {
            SubjectConcreto s = new SubjectConcreto();
 
            s.Registrar(new ObserverConcreto(s, "X"));
            s.Registrar(new ObserverConcreto(s, "Y"));
            s.Registrar(new ObserverConcreto(s, "Z"));
 
            s.SubjectState = "ABC";
            s.Notificar();
 
            Console.ReadKey();
        }

Iniciamos nossos Observers e já passamos como argumento no método Registrar. Quando mudamos o valor de s que é nosso Subject e Notificamos, o método Atualizar() dos Observers é executado e você verá o seguinte resultado:

No .Net também temos uma forma otimizada de fazer isso, usando delegates e events, que é muito mais simples e elegante, mas nada impede você de implementar essas classes da forma que vimos.

Há quem diga que Designs Patterns são na verdade "defeitos" das linguagens, se persarmos bem estão certos. O Observer é seria uma forma de usar delegates e events nas linguagens que não tem esses recursos, assim como vimos com o Singleton que pode ser implementado de forma muito mais simples no .Net. Até a herança que temos hoje, antigamente era um Design Pattern pra linguagens como C. Em assembly tinhamos um Pattern pra criar métodos! Que até então eram codigos que se repetiam por todo o programa, dificultando a manutenção. Mas continuando ao assunto principal...

Delegates são equivalentes aos ponteiros de função, mas orientado à objetos e "type-safe". Uma instncia de delegate mantém uma referência à um método instanciado ou de classe.

Events por sua vez, são construções declaradas numa classe pra ajudar a expor mudanças de estado aos objetos interessados, que são definidos em tempo de execução.  Um event representa os métodos Registrar, Desregistrar e Notificar que usamos no Observer, mas suportado diretamente pelo compilador e pela CLR.

Os delegates são registrados pra cada event desejado em tempo de execução e quando o event é chamado, todos os delegates registrados são invocados.

Fazendo uma comparação direta com o Design Pattern Observer, a classe que declara o event, seria o Subject, mas sem precisarmos criar Interfaces. E o Observer deve instanciar um delegate passando o nome do método a ser notificado e registrá-lo ao event. Também é possível desregistrar os delegates. A notificação do Subject acontece quando o event é invocado.

Pra quem não está acostumado com delegates e events pode parecer um pouco complicado, mas na verdade é bem mais simples, pois você não tem que se preocupar com Interfaces ou classes Base. Veja um exemplo:

    public class Estoque
    {
        //Declaração do delegate
        public delegate void DelegatePerguntaPreco(decimal pPreco);
        //Declaração do event
        public event DelegatePerguntaPreco PrecoMudou;
 
        //Variável observada
        decimal _Preco;
 
        public decimal Preco
        {
            set
            {
                _Preco = value;
 
                //Dispara o event
                PrecoMudou(_Preco);
            }
        }
    }
 
    public class TelaEstoque
    {
        public void MetodoPrecoMudou(decimal pPreco)
        {
            Console.Write("O novo preço é:" + pPreco.ToString("c") + "\r\n");
        }
    }
 
    public class MainClass
    {
 
        public static void Main()
        {
            TelaEstoque objTela = new TelaEstoque();//Observer
            Estoque objEstoque = new Estoque();//Subject
 
            //Cria novo delegate e associa ao método
            //objTela.MetodoPrecoMudou do Observer
            Estoque.DelegatePerguntaPreco aDelegate = new
               Estoque.DelegatePerguntaPreco(objTela.MetodoPrecoMudou);
 
            //Adiciona o delegate ao event
            objEstoque.PrecoMudou += aDelegate;
 
            //Muda o preco 10 vezes
            for (int i = 0; i < 10; i++)
            {
                objEstoque.Preco = i;
            }
 
            //Remove o delegate do event
            objEstoque.PrecoMudou -= aDelegate;
 
            Console.ReadKey();
        }
 
    }

 

A vantagem dos delegates além da simplicidade é que permite que qualquer classe atue como um Observer, independente das Interfaces implementadas ou da classe Base, só precisamos criar um método com a mesma assinatura do delegate.

Tags:

Artigos