Solucionado (ver solução)
Solucionado
(ver solução)
5
respostas

[Dúvida] Níveis de acessibilidade de atributos em interfaces

Boa tarde,

nas aulas de interfaces não é falado sobre a acessibilidade dos atributos, então acabei ficando com dúvida sobre a possibilidade de modificar o set Senha para protected, por exemplo. E se for possível, essa restrição ao acesso é efeito na interface ou no classe que implementa a interface?

Desde já agradeço.

5 respostas

Hugo,

Tranquilo... essas restrições podem ser colocadas em variáveis, propriedades, funções, interfaces... dependendo do caso, lógico.

São chamados de "modificadores de acesso", no C# os modificadores de acesso mais utilizados são:

  • public: acessível de qualquer ponto do código, ou seja não impõe restrições;
  • private: acessível somente dentro do contexto onde foi declarado, ou seja, um membro privado dentro de uma classe só é acessível dentro da própria classe;
  • protected: o elemento é acessível dentro da classe e suas derivadas;
  • internal: é o padrão no C#. Caso nenhum modificador seja declarado, definirá a acessibilidade do elemento dentro do executável ou dll onde foi declarado;
  • protected internal: é proveniente união dos modificadores protected e internal.

Segue um LINK legal para ler:

==========================================================

Modificadores de acesso (Guia de Programação em C#)

Artigo - 06/04/2023

Todos os tipos e membros de tipo têm um nível de acessibilidade. O nível de acessibilidade controla se eles podem ser usados em outro código no assembly ou em outros assemblies. Um assembly é um .dll ou .exe criado ao selecionar um ou mais arquivos .cs em uma única compilação. Use os modificadores de acesso a seguir para especificar a acessibilidade de um tipo ou membro quando você o declarar:

  • public: o tipo ou membro pode ser acessado por qualquer outro código no mesmo assembly ou em outro assembly que faz referência a ele. O nível de acessibilidade de membros públicos de um tipo é controlado pelo nível de acessibilidade do próprio tipo.
  • private: o tipo ou membro pode ser acessado somente pelo código na mesma class ou struct.
  • protected: o tipo ou membro pode ser acessado somente pelo código na mesma class ou em uma class derivada dessa class.
  • internal: o tipo ou membro pode ser acessado por qualquer código no mesmo assembly, mas não de outro assembly. Em outras palavras, tipos ou membros internal podem ser acessados no código que faz parte da mesma compilação.
  • protected internal: o tipo ou membro pode ser acessado por qualquer código no assembly no qual ele é declarado ou de uma class derivada em outro assembly.
  • private protected: o tipo ou membro pode ser acessado por tipos derivados do class, que são declarados no assembly relativo.

Tabela de resumo

Local do chamadorpublicprotected internalprotectedinternalprivate protectedprivate
Dentro da classe✔️✔️✔️✔️✔️✔️
Classe derivada (mesmo assembly)✔️✔️✔️✔️✔️
Classe não derivada (mesmo assembly)✔️✔️✔️
Classe derivada (assembly diferente)✔️✔️✔️
Classe não derivada (assembly diferente)✔️

https://learn.microsoft.com/pt-br/dotnet/csharp/programming-guide/classes-and-structs/access-modifiers

===============================================================

[]'s,

Fabio I.

Oi Fábio, bão?

Sim, entendo. Até li esse texto, mas lá não tem uma explicação sobre a implementação dos modificadores de acesso em interfaces.

Se eu modifico o acesso na interface, ainda consigo modificar os atributos sem o auxílio de métodos

Quando tento modificar o acesso na classe que implementa a interface, o erro que aparece é esse abaixo. Por isso me sugiu a dúvida nessa caso.Insira aqui a descrição dessa imagem para ajudar na acessibilidade

Hugo,

Consegui emular o erro aqui! O problema é esse PRIVATE de herança.

using bytebank_ADM.SistemaInterno;

namespace bytebank_ADM.Parceria
{
    public class ParceiroComercial:IAutenticavel
    {       
        public string Senha { get; private set; }        

        public bool Autenticar(string senha)
        {
            return this.Senha == senha;
        }
    }
}
  • Gravidade: Erro
  • Código: CS0277
  • Descrição: "ParceiroComercial" não implementa membro de interface "IAutenticavel.Senha.set". "ParceiroComercial.Senha.set" não é público.
  • Projeto: bytebank_ADM
  • Arquivo: ParceiroComercial.cs
  • Linha: 5
  • Estado de Supressão: Ativo

Vamos tentar entender...

===============================================================

Erro do Compilador CS0277

Artigo - 06/04/2023

"class" não implementa o membro da interface "accessor". "class accessor" não é público

Esse erro ocorre quando você tenta implementar uma propriedade de uma interface, mas a implementação do acessador de propriedade na classe não é pública. Os métodos que implementam membros da interface precisam ter acessibilidade pública. Para resolver, remova o modificador de acesso do acessador de propriedade.

Exemplo

O seguinte exemplo gera o erro CS0277:

// CS0277.cs  
public interface MyInterface  
{  
    int Property  
    {  
        get;  
        set;  
    }  
}  

public class MyClass : MyInterface   // CS0277  
{  
    public int Property  
    {  
        get { return 0; }  
        // Try this instead:  
        //set { }  
        protected set { }  
    }  
}

https://learn.microsoft.com/pt-br/dotnet/csharp/misc/cs0277

===============================================================

Neste caso a propriedade SET da interface HERDADA está um mais restrição do que da origem na interface.

Acredito que NÃO pode fazer isso por regra do próprio C#... agora NÃO entendi se é obrigatório usar "PUBLIC" sempre...

... TESTANDO JÁ!

namespace bytebank_ADM.SistemaInterno
{
    public interface IAutenticavel
    {
        public string Senha { get; private protected set; }
        public bool Autenticar(string senha);

    }
}
using bytebank_ADM.SistemaInterno;

namespace bytebank_ADM.Parceria
{
    public class ParceiroComercial:IAutenticavel
    {
        public string Senha { get; set; }        

        public bool Autenticar(string senha)
        {
            return this.Senha == senha;
        }
    }
}

O "Private Protected" deixa a classe derivada usá-lo, portanto, segundo a planilha acima, é permitido herdar. Assim funciona, NÃO precisa ser sempre PUBLIC, só NÃO pode ser PRIVATE, pois o PRIVATE NÃO deixa a INTERFACE herdar. Mas que herda precisa herdar o que estiver na interface ... ou não? Não aceita nem se eu colocar explicitamente PUBLIC no SET do "ParceiroComercial".

RESUMINDO:

Se você colocar a restrição na própria interface, tudo bem, mas só NÃO pode ser do tipo PRIVATE, pois essa NÃO permite a herança trabalhar. Quem herda (ParceiroComercial) NÃO pode ter NENHUM modificador de acesso, nem mesmo PUBLIC... isso eu achei estranho...

[]'s,

Fabio I.

solução!

Devido a própria natureza do conceito de interface, o uso de um modificador private, por exemplo, não teria sentido. A interface é um contrato público em que você define o mínimo que cada implementação precisará expor. Não importa pra ela a implementação, desde que sigam as assinaturas impostas por ela.

Vamos supor que essa propriedade esteja na sua interface:

public string Senha { get; private protected set; }

Quando você for trabalhar com uma implementação através da interface, você nem verá o "Set". Se a interface é responsável por definir o contrato público, por que ela se importaria se sua implementação tem um set privado ou não? Mesma coisa para métodos privados. Se ela não vai expor esse método, por que ela deveria se importar se a implementação usa ou não um método privado?

O importante para você aí é somente o que poderá ser acessado via interface. No seu caso, apenas o Get da propriedade.

public string Senha { get; }

Se ele usa um Set privado, protegido, etc. Não importa para a interface. Você coloca lá na sua implementação somente. Se esse tipo de restrição é importante para você, como obrigar a implementação de um método de outro escopo, que não seja o público, talvez seja melhor usar uma classe abstrata ao invés de uma interface.

Repensado depois, eu acabei tirando a implementação dos atributos e deixando apenas nas classes que iriam implementar a interface em questão. Já que eu teria que declarar os atributos na interface e na classe que a implementa. Depois disso, aí sim modifiquei os acessos.

Muito obrigado pela explicação, fez muito mais sentido agora!