{"id":187,"date":"2025-01-01T07:55:05","date_gmt":"2025-01-01T10:55:05","guid":{"rendered":"http:\/\/wagnersalvi.eti.br\/?p=187"},"modified":"2025-03-04T23:30:09","modified_gmt":"2025-03-05T02:30:09","slug":"uso-de-classes-e-metodos-genericos-em-c","status":"publish","type":"post","link":"http:\/\/www.wagnersalvi.com.br\/?p=187","title":{"rendered":"Uso de Classes e M\u00e9todos Gen\u00e9ricos em c#"},"content":{"rendered":"\n<p>Classes e M\u00e9todos Gen\u00e9ricos permitem que n\u00e3o sejam especificados os tipos at\u00e9 que sejam declarados e instanciados pelo c\u00f3digo. Os gen\u00e9ricos s\u00e3o usados com mais frequ\u00eancia com cole\u00e7\u00f5es e com os m\u00e9todos que operam nelas e que podem ser usados para desenvolvimento de classes que pegam dados do banco de dados e jogam em classes que servem como Camada Modelo dentro de um modelo MVC por exemplo.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">Exemplo de Classe Gen\u00e9rica:\nExplicar\npublic class ListaGenerica&lt;T>\n{\n    public void Add(T input) { }\n}\n\n\/\/Eu posso posteriormente instanciar e inicializar como\n\n\/\/ Inteiro\nListaGenerica&lt;int> Lista1 = new ListaGenerica&lt;int>();\nLista1.Add(1);\n\n\/\/ String\nListaGenerica&lt;string> Lista2 = new ListaGenerica&lt;string>();\nLista2.Add(\u201cTeste\u201d);\n\n\/\/ Outra classe qualquer\nListaGenerica&lt;QualquerClass> Lista3 = new ListaGenerica&lt; QualquerClass >();\nLista3.Add(new QualquerClass);<\/pre>\n\n\n\n<p>Agora vamos aplicar esta funcionalidade num modelo pratico onde crio um m\u00e9todo que pego um Select consulto no banco de dados, jogando num DataReader, deste DataReader iremos jogar nas classes que fazem papel de Model no modelo MVC.<\/p>\n\n\n\n<p>Sem usar Gen\u00e9ricos para cada tabela voc\u00ea repetiria muitos dos m\u00e9todos, tornando complicado e mais demorado para dar manuten\u00e7\u00e3o, maiores chances de erros, etc. Se utilizando de Heran\u00e7as, Generics, classes abstratas, podemos criar M\u00e9todos de busca de dados no banco que podem ser usadas para qualquer classe que fa\u00e7a papel de Model, variando praticamente somente a parte de pegar do datareader para a classe modelo, por obviamente cada tabela do banco e classe Model que a representa ter campos diferentes. Vamos considerar o cen\u00e1rio no banco de dados:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td><strong>Usuarios<\/strong><\/td><td>&nbsp;<\/td><td>&nbsp;<\/td><td><\/td><td><strong>Produtos<\/strong><\/td><td>&nbsp;<\/td><td>&nbsp;<\/td><\/tr><tr><td><strong>Campo<\/strong><\/td><td><strong>Tipo<\/strong><\/td><td><strong>Tamanho<\/strong><\/td><td><\/td><td><strong>Campo<\/strong><\/td><td><strong>Tipo<\/strong><\/td><td><strong>Tamanho<\/strong><\/td><\/tr><tr><td>Chave<\/td><td>INT<\/td><td>&nbsp;<\/td><td><\/td><td>Chave<\/td><td>INT<\/td><td>&nbsp;<\/td><\/tr><tr><td>Usuario<\/td><td>Varchar<\/td><td>50<\/td><td><\/td><td>Codigo<\/td><td>Varchar<\/td><td>30<\/td><\/tr><tr><td>Senha<\/td><td>Varchar<\/td><td>50<\/td><td><\/td><td>Descricao<\/td><td>Varchar<\/td><td>100<\/td><\/tr><tr><td><\/td><td><\/td><td><\/td><td><\/td><td>Estoque<\/td><td>Float<\/td><td>&nbsp;<\/td><\/tr><tr><td><\/td><td><\/td><td><\/td><td><\/td><td>Preco<\/td><td>Float<\/td><td>&nbsp;<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Logo temos a representa\u00e7\u00e3o dos modelos das duas tabelas acima da seguinte forma e vamos conforme <a href=\"http:\/\/wagnersalvi.eti.br\/?p=184\" data-type=\"link\" data-id=\"http:\/\/wagnersalvi.eti.br\/?p=184\">post <\/a>anterior j\u00e1 se aproveitar do conceito de Heran\u00e7a onde herda de BaseModel que tem o atributo Chave que ser\u00e1 comum em todas tabelas do banco de dados:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">public class UsuarioModel : BaseModel\n{ \n      [DisplayName(\"Usu\u00e1rio do Sistema\")]\n      public string Usuario { get; set; }\n\n      [DisplayName(\"Senha\")]\n      public string Senha { get; set; }\n}\n\npublic class ProdutoModel : BaseModel\n{ \n      [DisplayName(\"C\u00f3digo do Produto\")]\n      public string Codigo{ get; set; }\n\n      [DisplayName(\"Descri\u00e7\u00e3o\")]\n      public string Descricao { get; set; }\n\n      [DisplayName(\"Estoque Total\")]\n      public double Estoque { get; set; }\n\n      [DisplayName(\"Pre\u00e7o em R$\")]\n      public double Preco { get; set; }\n\n}<\/pre>\n\n\n\n<p>Acima temos as duas classes que tem atributos diferentes tanto em quantidade de atributos como em tipos diferentes. Ent\u00e3o vamos agora construir as classes de acesso a banco de dados de forma gen\u00e9rica e abstrata (classes que n\u00e3o s\u00e3o instanci\u00e1veis e servem de base para outros objetos) para que fa\u00e7a a coleta dos dados no banco de dados, jogue pra um dataReader e este jogue para a classe de usuarios e produtos.<\/p>\n\n\n\n<p>Primeiro vamos criar uma classe que retire os dados de um DBDataReader e jogue em uma classe ConversorDataReader dentro de um array de string com as colunas que ser\u00e1 usado posteriormente<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">public sealed class ConversorDataReader \n{\n        #region Atributos\n        private readonly DbDataReader dbDataReader;\n        private readonly string[] colunas;\n        #endregion\n\n        #region Construtores\n        public ConversorDataReader (DbDataReader dbDataReader)\n        {\n            this.dbDataReader = dbDataReader ?? throw new ArgumentNullException(nameof(dbDataReader));\n            this.colunas = new string[dbDataReader.FieldCount];\n\n            for (int i = 0; i &lt; dbDataReader.FieldCount; i++)\n                this.colunas[i] = dbDataReader.GetName(i);\n        }\n        #endregion\n        \n        \/\/ M\u00e9todo para retornar uma string do dbDataReader\n        public string ConverterString(string nomeColuna)\n        {\n            return this.dbDataReader[nomeColuna].ToString();\n        }\n\n        \/\/ M\u00e9todo para retornar uma Inteiro dbDataReader\n        public int? ConverterInt32(string nomeColuna)\n        {\n            return Convert.ToInt32(this.dbDataReader[nomeColuna]);\n        }\n\n}<\/pre>\n\n\n\n<p>Criaremos a classe AcessoBaseDados que recebe uma classe Generica T, que posteriormente iremos usar passando a classe Modelo desejada, neste caso usamos a classe System.Data.SqlCLient (SqlServer)<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">public abstract class AcessoBaseDados&lt;T>\n{   \n      \/\/ classe abstrata que devera ser implementada quando instanciar classe herdada de AcessoBaseDados\n      protected abstract T CriaRegistro(ConversorDataReader conversorDataReader);\n\n      \/\/ classe que ir\u00e1 executar o comando sql passado por parametro e retornar uma classe que instanciar T\n      protected ObservableCollection&lt;T> BuscarRegistros(string commandText)\n      {\n            \/\/ Cole\u00e7\u00e3o de T genericos que ir\u00e1 retornar ao fim do metodo \n            ObservableCollection&lt;T> registros = new ObservableCollection&lt;T>();\n\n            \/\/ configura\u00e7\u00e3o de conex\u00e3o\n            SqlConnection conexao = new SqlConnection();\n            conexao.ConnectionString = &lt;connectionString a ser usada>;\n\n            try\n            {\n                \/\/ cria\u00e7\u00e3o do comando que ser\u00e1 executado\n                SqlCommand comando= new SqlCommand\n                {\n                     CommandText = commandText,\n                };\n\n                \/\/ abrindo conex\u00e3o\n                commando.Connection = conexao ;\n                commando.Connection.Open();\n \n                \/\/ Criando dataReader com o resutlado do ExecuteReader\n                using (SqlDataReader sqlDataReader = sqlCommand.ExecuteReader())\n                {\n                     while (sqlDataReader.Read())\n                     {\n                        \/\/ para cada registro retorndo do bando e dentro do dataReader, ser\u00e1 cridoa dum registro do tipo T e adicionado na lista de \n                         registros\n                        var registro = this.CriaRegistro(new ConversorDataReader (sqlDataReader));\n                        registros.Add(registro);\n                     }\n                     sqlDataReader.Close();\n                }\n            }\n            catch (SqlException)\n            {\n                throw;\n            }\n            finally\n            {\n               if (commando!= null)\n                  commando.Dispose();\n               if (conexao!= null)\n                  conexao.Dispose();\n             }\n             \/\/ retornando a lista de  registros\n             return registros;\n        }\n}<\/pre>\n\n\n\n<p>Acima temos alguns pontos importantes que destacamos<\/p>\n\n\n\n<p>Criamos a classe abstrata CriaRegistro que ela somente serve como Modelo para quando for instanciado esta classe esta sim ter\u00e1 para cada classe modelo sua implementacao diferente, para seus atributos diferentes. Ela retorna um tipo Gen\u00e9rico T que ser\u00e1 as classes modelos<\/p>\n\n\n\n<p>Criamos a classe BuscaRegistros que retorna uma ObservableCollection Gen\u00e9rica (que poderia ser qualquer tipo de lista desejada como List por exemplo e dentro dela fazemos a conex\u00e3o com banco de dados e usando o parametro de entrada commandText que ser\u00e1 o select a ser executado, ir\u00e1 gerar uma lista com os registros que resultarem deste select.. Veja que ele executa o select (executeReader) e pra cada registro passara no metodo CriaRegistro que retornar\u00e1 o registro no Tipo T Generico e ser adicionado na lista \u201cregistros\u201d que \u00e9 uma cole\u00e7ao de objeto do Tipo T Gen\u00e9rico.<\/p>\n\n\n\n<p>Desta forma, at\u00e9 o momento n\u00e3o nos importamos com os atributos que ser\u00e3o tratados dentro da classe, podendo ser usada para qualquer modelo ent\u00e3o a partir de agora sempre que se conectar no banco pode ser usado este M\u00e9todo Gen\u00e9rico j\u00e1 trazendo os dados para a classe modelo desejada<\/p>\n\n\n\n<p>Vamos agora implementar o uso destas , mas agora sim com as classes Model inicialmente criadas, onde tomaremos por exemplo a classe UsuarioViewModel que vai herdar de AcessoBasedados e onde estava o T Gen\u00e9rico agora ter\u00e1 a classe desejada<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">public class UsuarioViewModel : AcessoBaseDados&lt;UsuarioModel>\n{\n    \/\/ Construtor\n    public UsuarioViewModel ()\n    {\n    }\n    \n    public void RetornaLista()\n    {\n       \/\/ defino o select a ser usado\n       string comando = \"SELECT CHAVE, USUARIO, SENHA FROM USUARIOS\"\n       \/\/ crio uma lista que recebera os dados do select\n      \n       ObservableCollection&lt;UsuarioModel> ListaUsuarios = new ObservableCollection&lt;UsuarioModel>;\n       \/\/ fa\u00e7o chamada do Buscar Registros\n       ListaUsuarios = BuscarRegistros(comando);\n    }\n    \n    \/\/ Override (sobrescrita) da classe abstrata CriaRegistro mas retornando agora no modelo desejado\n    protected override UsuarioModel CriaRegistro(ConversorDataReader conversorDataReader )\n    {\n            UsuarioModel registro = new UsuarioModel ();\n\n            registro.Chave = conversorDataReader.ConverterInt32(\"CHAVE\");\n            registro.Usuario= conversorDataReader.ConverterString(\"USUARIO\");\n            registro.Senha= conversorDataReader.ConverterString(\"SENHA\");\n\n            return registro;\n    }\n}<\/pre>\n\n\n\n<p>No c\u00f3digo acima podemos verificar que retornar registros de usuarios (UsuarioModel) ou qualquer outra classe (poderia ser por exemplo a ProdutoModel \u00e9 bem simples basta seguir os seguintes passos:<\/p>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li>Criar a classe herdando da AcessoBaseDados e passando que classe Model voce deseja usar;<\/li>\n\n\n\n<li>Criar um m\u00e9todo qualquer onde voce criar\u00e1 uma Lista da Classe Model desejada (deve ser a mesma da cria\u00e7\u00e3o da classe) ;<\/li>\n\n\n\n<li>Dentro deste m\u00e9todo basta passar o comando sql para o metodo que vem herdado de AcessoBaseDados que ele ir\u00e1 executar e retornar no tipo de Dados (Classe Model) que voce criou o objeto;<\/li>\n\n\n\n<li>Fazer o Override da Classe CriaRegistro onde voce faz o de-para do datareader para a classe desejada;<\/li>\n<\/ol>\n\n\n\n<p>Toda quest\u00e3o de conex\u00e3o com banco de dados, (abrir , fechar conex\u00e3o, montar o command, criar dataReader, ler cada registro do datareader) est\u00e1 pronto para ser usado para qualquer tipo de classe desejada e n\u00e3o precisa ser desenvolvido para cada tabela do banco de dados o que geraria muito trabalho para dar manuten\u00e7\u00e3o e mais c\u00f3digo a ser escrito, ficando somente o que \u00e9 essencialmente particular para cada tipo de dados para ser programado no local desejado.<\/p>\n<p>Views: 0<\/p>","protected":false},"excerpt":{"rendered":"<p>Classes e M\u00e9todos Gen\u00e9ricos permitem que n\u00e3o sejam especificados os tipos at\u00e9 que sejam declarados e instanciados pelo c\u00f3digo. Os [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":141,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[49],"tags":[43],"class_list":["post-187","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-programacao","tag-programacao"],"_links":{"self":[{"href":"http:\/\/www.wagnersalvi.com.br\/index.php?rest_route=\/wp\/v2\/posts\/187","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.wagnersalvi.com.br\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.wagnersalvi.com.br\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.wagnersalvi.com.br\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.wagnersalvi.com.br\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=187"}],"version-history":[{"count":0,"href":"http:\/\/www.wagnersalvi.com.br\/index.php?rest_route=\/wp\/v2\/posts\/187\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"http:\/\/www.wagnersalvi.com.br\/index.php?rest_route=\/wp\/v2\/media\/141"}],"wp:attachment":[{"href":"http:\/\/www.wagnersalvi.com.br\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=187"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.wagnersalvi.com.br\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=187"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.wagnersalvi.com.br\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=187"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}