none
Dúvida de iniciante sobre instanciar variáveis. RRS feed

  • Pergunta

  • Olá Pessoal,

    Iniciei há mais ou menos uma semana os estudos com C# e mysql. Ainda me acostumando com a orientação a objetos. Como primeiro programa, estou tentando uma coisa bem simples: gravar um texto digitado em um richtextbox em um banco de dados. A parte de conexão ao banco, gravação, está tudo ok. Apenas tenho duvida prática de como puxar o valor que uma variável que está numa classe para ser mostrada em outra.

    Meu Form1 está na clase Form1 e o procedimento pra salvar no banco de dados foi escrito em outra classe, a classe DB. Criei uma variável para onde joguei o valor do richtextbox no Form1. Ao salvar no banco de dados quero pegar o valor dessa variável que possui o conteúdo do richtextbox e jogar nos parâmetros de salvamento do banco de dados, algo mais ou menos assim:

    ... = "INSERT INTO table1 (nome, texto) VALUES('Fulano','" + Variável + "')";

    Bom, pelo que entendi teria que criar um objeto, instanciando a classe Form1, assim:

    Form1 Form1 = new Form1();

    Daí bastaria usar Form1.Variável  - O problema é que ao instanciar o Form1 ele "constrói" uma cópia do Form1 e apaga o que eu digitei no richtextbox, fazendo com que nada fosse salvo no banco de dados. 

    Pesquisei e vi que se eu criar essa variável como static e poderia chamá-la em outra classe sem instanciar, daí ela não perderia seu valor. Porém, li que isso não seria uma boa prática em orientação a objetos, pois iria se perder o conceito encapsulamento.

    Isso procede? Se sim, como passar o valor do conteúdo que está no richtextbox para outra classe sem apagá-lo quando a classe é instanciada? existe algum método pra salvar esse valor em algum lugar sem perder o valor após o instanciamento ou terei mesmo que usar a variável static?

    Desde já agradeço e peço desculpas se falei alguma bobagem. Começando do zero mesmo.

    terça-feira, 27 de maio de 2014 00:32

Respostas

  • Olá Denis,

    Se você tem como objetivo que essa seja uma "variável global", que se usa em qualquer classe não tem problema declarar a mesma como "public static nomeVariavel;".

    O que pode ser feito também é salvar a variável no banco (como você esta fazendo) e fazer um "select" no banco para chamar na outra classe, exemplo "select nome, texto from table1".

    terça-feira, 27 de maio de 2014 01:47
  • Olha, realmente membros estáticos pertencem à classe, não à instância. Por isso você pode chamá-los mesmo sem ter instanciado um objeto da classe à qual eles pertencem. Quanto a perder o encapsulamento... hmmm... Não vejo desta forma. Como disse, membros estáticos apenas independem de objetos. Se você criar um atributo  estático e privado em outra classe e um método de acesso também estático e público, com o devido tratamento de acesso, você terá um atributo estático e encapsulado! 

    Já com relação a passar um conteúdo de uma classe para outra, você pode criar um método na classe DB que recebe uma string como parâmetro e grava este conteúdo no banco. Daí basta invocar este método da classe Form1 e passar um parâmetro no formato string. Por exemplo:

    Na classe DB:

       class DB
        {
            public void MetodoGravar(string valor)
            {
               /*
                * escreva aqui os procedimentos para gravação no banco
                */ 
            }
        }

    E na classe Form1 você pode passar o parâmetro no clique do mouse, por exemplo:

      public partial class Form1 : Form
        {
          
            public Form1()
            {
                InitializeComponent();
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                var objDB = new DB();
                objDB.MetodoGravar(richTextBox1.Text);
            }
        }

     
    terça-feira, 27 de maio de 2014 01:48
  • Você quer passar informações para outra classe, poderia usar uma classe modelo e utilizar métodos Get(),Set(), assim você estaria dentro dos padrões de encapsulamento.
    terça-feira, 27 de maio de 2014 11:11
  • Denis, não tente fazer programação de alta performance logo de cara, a não ser que vc vá programar para mainframe.

    Siga a dica do nosso caro amigo Winicius Dutra crie uma classe, instancia e passa para o método via parâmetro.

    Uma vez que C# ja possui um controlador de memória, assim que vc encerrar todos os processos com essa classe, a mesma será destruída e eliminada da memoria.

    terça-feira, 27 de maio de 2014 11:20
  • Com relação à pergunta sobre membros estáticos: não é aconselhável deixar tudo como estático. Isso por que membros estáticos tem várias limitações. Por exemplo, se todos forem estáticos terão sempre os mesmos valores. Imagine que você tenha uma classe "Pessoa" e precise representar duas pessoas distintas com objetos dessa classe. Se o atributo "nome" for estático, então ele será o mesmo para todos os objetos do tipo Pessoa. Além disso, membros estáticos não são acessíveis a partir de objetos instanciados. Outra limitação é que eles permanecem na memória enquanto a aplicação estiver aberta, dessa forma você não estaria economizando memória, como você supôs.

    Uma curiosidade: você pode criar uma classe inteira como estática. Mas aí vem as limitações: todos os membros terão que ser estáticos, essa classe não poderá ser instanciada, será uma classe selada e não poderá conter construtores. Um exemplo de classe estática que já vem no .NET é a classe "Math".

    A sua última pergunta está meio confusa. Não é possível salvar o conteúdo de uma variável antes de instanciá-la. Funciona assim: você instancia, passa o valor e, se quiser que esse valor seja mantido, terá que salvar em algum lugar, que pode ser um banco de dados, um arquivo .txt, .xml, .dat... Por que depois que não houver referência ao seu objeto ou o aplicativo for encerrado, o valor será perdido.

    terça-feira, 27 de maio de 2014 11:33
  • Denis, sugiro você ler esse artigo sobre singleton, static e variáveis globais: artigo
    terça-feira, 27 de maio de 2014 11:45

Todas as Respostas

  • Olá Denis,

    Se você tem como objetivo que essa seja uma "variável global", que se usa em qualquer classe não tem problema declarar a mesma como "public static nomeVariavel;".

    O que pode ser feito também é salvar a variável no banco (como você esta fazendo) e fazer um "select" no banco para chamar na outra classe, exemplo "select nome, texto from table1".

    terça-feira, 27 de maio de 2014 01:47
  • Olha, realmente membros estáticos pertencem à classe, não à instância. Por isso você pode chamá-los mesmo sem ter instanciado um objeto da classe à qual eles pertencem. Quanto a perder o encapsulamento... hmmm... Não vejo desta forma. Como disse, membros estáticos apenas independem de objetos. Se você criar um atributo  estático e privado em outra classe e um método de acesso também estático e público, com o devido tratamento de acesso, você terá um atributo estático e encapsulado! 

    Já com relação a passar um conteúdo de uma classe para outra, você pode criar um método na classe DB que recebe uma string como parâmetro e grava este conteúdo no banco. Daí basta invocar este método da classe Form1 e passar um parâmetro no formato string. Por exemplo:

    Na classe DB:

       class DB
        {
            public void MetodoGravar(string valor)
            {
               /*
                * escreva aqui os procedimentos para gravação no banco
                */ 
            }
        }

    E na classe Form1 você pode passar o parâmetro no clique do mouse, por exemplo:

      public partial class Form1 : Form
        {
          
            public Form1()
            {
                InitializeComponent();
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                var objDB = new DB();
                objDB.MetodoGravar(richTextBox1.Text);
            }
        }

     
    terça-feira, 27 de maio de 2014 01:48
  • Agradeço muito as duas repostas até agora.

    Só adicionar um pensamento: não seria sempre bom colocar todas as variáveis como static, já que se for instanciá-las eu teria que criar um objeto com todo o conteúdo, por exemplo, de uma classe grande como a classe Form1? Eu não estaria alocando mais espaço na memória de forma desnecessária só para chamar uma única variável?

    Então, pelo que entendi, se quiser sempre instanciar uma variável terei sempre que salvar o conteúdo dela em um arquivo ou banco de dados antes de instanciar, certo?

    terça-feira, 27 de maio de 2014 02:28
  • Você quer passar informações para outra classe, poderia usar uma classe modelo e utilizar métodos Get(),Set(), assim você estaria dentro dos padrões de encapsulamento.
    terça-feira, 27 de maio de 2014 11:11
  • Denis, não tente fazer programação de alta performance logo de cara, a não ser que vc vá programar para mainframe.

    Siga a dica do nosso caro amigo Winicius Dutra crie uma classe, instancia e passa para o método via parâmetro.

    Uma vez que C# ja possui um controlador de memória, assim que vc encerrar todos os processos com essa classe, a mesma será destruída e eliminada da memoria.

    terça-feira, 27 de maio de 2014 11:20
  • Com relação à pergunta sobre membros estáticos: não é aconselhável deixar tudo como estático. Isso por que membros estáticos tem várias limitações. Por exemplo, se todos forem estáticos terão sempre os mesmos valores. Imagine que você tenha uma classe "Pessoa" e precise representar duas pessoas distintas com objetos dessa classe. Se o atributo "nome" for estático, então ele será o mesmo para todos os objetos do tipo Pessoa. Além disso, membros estáticos não são acessíveis a partir de objetos instanciados. Outra limitação é que eles permanecem na memória enquanto a aplicação estiver aberta, dessa forma você não estaria economizando memória, como você supôs.

    Uma curiosidade: você pode criar uma classe inteira como estática. Mas aí vem as limitações: todos os membros terão que ser estáticos, essa classe não poderá ser instanciada, será uma classe selada e não poderá conter construtores. Um exemplo de classe estática que já vem no .NET é a classe "Math".

    A sua última pergunta está meio confusa. Não é possível salvar o conteúdo de uma variável antes de instanciá-la. Funciona assim: você instancia, passa o valor e, se quiser que esse valor seja mantido, terá que salvar em algum lugar, que pode ser um banco de dados, um arquivo .txt, .xml, .dat... Por que depois que não houver referência ao seu objeto ou o aplicativo for encerrado, o valor será perdido.

    terça-feira, 27 de maio de 2014 11:33
  • Denis, sugiro você ler esse artigo sobre singleton, static e variáveis globais: artigo
    terça-feira, 27 de maio de 2014 11:45
  • Como seria um exemplo bem simples de passar uma variável de uma classe pra outra usando get() set()? Por exemplo:  Declarei assim uma variável:

      private string Rico;
    
            public string Rico1
            {
                get { return Rico; }
                set { Rico = value; }
            }


    Depois atribuo um valor a ela na classe Form1 (onde foi criada), quando clico no botão salvar:

      private void button2_Click(object sender, EventArgs e)
                {
                    Rico1 = richTextBox1.Rtf;
                }


    Aí chamo ela na classe DBConnect, dentro de um método Insert:

       Form1 Form1 = new Form1();
    
                string query = "INSERT INTO table1 (nome, texto) VALUES('Neusita Smith','" + Form1.Rico1.Replace(@"\", @"\\") + "')";


    Daí sempre que salvo algo me dá esse erro: 

    An unhandled exception of type 'System.NullReferenceException' occurred in WindowsFormsApplication1.exe

    Additional information: Object reference not set to an instance of an object.

    O que está errado? Parece que Rico1 vem zerada. Então assim que instanciei a classe Form1 ela apagou o valor de Rico1 que estava guardado?


    quarta-feira, 28 de maio de 2014 19:23
  • Saquei agora, que burro que sou!!!

    Negócio é construir um construtor personalizado na classe DBConnect.

    Este construtor personalizado vai receber o valor da variável que possui o conteúdo do richtextbox.

    Assim, fiz:

     private void button2_Click(object sender, EventArgs e)
                {
                    Rico1 = richTextBox1.Rtf;
           
    
           
                    DBConnect myclass = new DBConnect(Rico1);
                }

    Quando chamo a classe DBConnect, passando um parâmetro ela usa o construtor personalizado que criei, e leva consigo já o valor de "Rico1":

       public DBConnect(string Parametro)
            {
                Initialize();
            
                Anta =  Parametro;
            }

    Daí "Anta" já carrega o valor do richtextbox1 da classe Form1.

    Valeu pessoal, desculpem a noobice, mas depois de lidar com Clipper em 1995 durante 1 ano e ficar parado até semana passada, voltar numa linguagem de orientação a objetos é um porrada grande. Muita ferrugem pra ser tirada!! Agradeço a todos que respoderam. Li todos os textos sugeridos e vou continuar aprendendo bastante. Obrigado!!

    quarta-feira, 28 de maio de 2014 21:23
  • Magina, estamos todos aqui aprendendo um com o outro.

    Só uma dica, normalmente é legal você criar um método de inserção e dentro desse método realizar a conexão com banco, pegar os dados passados por parâmetros e realizar inserção dos dados, fechar conexão.

    Abraço e sucesso.
    • Editado Elton Martins quarta-feira, 28 de maio de 2014 21:34 erro digitação
    quarta-feira, 28 de maio de 2014 21:33
  • Valeu! Já criei um método de abertura, outro de inserção e outro pra encerrar a conexão ao bando de dados!
    quinta-feira, 29 de maio de 2014 14:48