20 perguntas da entrevista C# (para calouros) 2023

Olá, amantes de C#! Então você cobriu o básico e agora está ansioso para responder a algumas perguntas mais desafiadoras da entrevista, hein? Talvez você seja um novato querendo impressionar em sua primeira entrevista ou apenas tentando desenvolver seu conhecimento em C#. Adivinha? Você veio ao lugar certo, meu amigo!

Neste artigo, vamos nos aprofundar em 20 ótimas perguntas de entrevista em C# para iniciantes; um degrau acima do básico, mas ainda assim totalmente factível. Entre essas questões, você encontrará uma variedade de questões para testar seu raciocínio lógico, habilidades de análise de código e conceitos de programação muito importantes.

Pronto para surpreender seus entrevistadores?

pode vir!

O que são namespaces em C#?
Resposta
Namespaces em C# são uma forma de agrupar tipos relacionados e melhorar a organização do código. É usado para evitar conflitos de nomenclatura entre diferentes classes ou tipos que possam ter o mesmo identificador. Os namespaces funcionam como uma hierarquia, dentro da qual você pode aninhar namespaces, e eles podem abranger vários arquivos ou até mesmo bibliotecas.

Por exemplo:

namespace Company.Project
{
    
    
    class MyClass
    {
    
    
        // Class implementation
    }
}

Neste exemplo, a classe MyClass é declarada no namespace Company.Project.

Qual é o propósito da diretiva “using” em C#?
Resposta
A diretiva using em C# tem dois propósitos principais:

Importação de namespace: using permite importar um namespace para que você possa usar tipos e membros definidos nesse namespace sem especificar seus nomes completos. Isso torna seu código mais legível e reduz a complexidade do código. Por exemplo:

using System;

    class Program
    {
    
    
        static void Main()
        {
    
    
            // Without the 'using' directive, you would need to write: System.Console.WriteLine("Hello, World!");
            Console.WriteLine("Hello, World!");
        }
    }

Gerenciamento de recursos: a instrução using é usada para ajudá-lo a gerenciar recursos que implementam a interface IDisposable, como fluxos de arquivos, conexões de rede ou conexões de banco de dados. A instrução using garante que o método Dispose() seja chamado no recurso quando o bloco de código for encerrado, liberando assim o recurso adequadamente. Por exemplo:

using System.IO;

    class Program
    {
    
    
        static void Main()
        {
    
    
            using (StreamReader reader = new StreamReader("file.txt"))
            {
    
    
                // Code to read from the file
            } // At this point, the Dispose() method of the StreamReader is automatically called, releasing resources.
        }
    }

Quais são os tipos de referência em C#?
Resposta
Um tipo de referência em C# é um tipo que armazena uma referência a um local de memória que armazena dados, não os dados em si. Ao criar objetos a partir de classes ou usar matrizes, delegados, interfaces ou a maioria das estruturas de dados internas no .NET Framework, você estará usando tipos de referência. Ao contrário dos tipos de valor, os tipos de referência são alocados no heap e sua memória é gerenciada pelo coletor de lixo.

Aspectos principais dos tipos de referência:

Quando você passa um tipo de referência como parâmetro de método ou o atribui a outra variável, ambas as variáveis ​​referem-se ao mesmo local de memória. Portanto, a modificação de uma variável afetará a outra variável.
Os tipos de referência podem ter um valor nulo, o que significa que não se referem a nenhum local ou objeto de memória.

class Person
{
    
    
    public string Name {
    
     get; set; }
}

Person person1 = new Person {
    
     Name = "John" };
Person person2 = person1; // Both person1 and person2 reference the same object in memory
person2.Name = "Jane"; // Changing person2.Name also updates person1.Name, as they both refer to the same object

Como declarar métodos em C#?
Resposta
Um método em C# é um bloco de código que executa uma tarefa específica e pode ser chamado quantas vezes forem necessárias. Para declarar um método, você especifica seu nível de acesso, tipo de retorno, nome do método e lista de parâmetros (se aplicável) na classe. Aqui está um exemplo:

public class Calculator
{
    
    
    public int Add(int a, int b)
    {
    
    
        int sum = a + b;
        return sum;
    }
}

Adicionar Neste exemplo, declaramos um método nomeado com o modificador de acesso público, um tipo de retorno int e dois parâmetros do tipo int. Este método calcula a soma de dois números e retorna o resultado.

Quais são os modificadores de acesso básicos disponíveis em C#?
Os modificadores de acesso de resposta
em C# controlam a visibilidade e acessibilidade dos membros da classe (métodos, propriedades, campos, etc.) e da própria classe. Os modificadores de acesso básicos disponíveis em C# são:

public: Membros e classes com o modificador de acesso public podem ser acessados ​​a partir de qualquer código no mesmo assembly ou em outro assembly que o faça referência.
private: membros declarados como privados só podem ser acessados ​​dentro da mesma classe. Eles não são visíveis para outras classes, mesmo dentro do mesmo assembly. private Por padrão, um membro da classe se nenhum modificador de acesso for especificado.
protegido: membros declarados com o modificador de acesso protegido podem ser acessados ​​na mesma classe, bem como em classes derivadas. Eles não são visíveis para outras classes não derivadas no mesmo assembly.
Interno: membros e classes com o modificador de acesso interno podem ser acessados ​​em qualquer lugar na mesma montagem, mas não são visíveis para outras montagens.
protegido por dentro: membros declarados com o modificador de acesso interno protegido podem ser acessados ​​no mesmo assembly ou por classes derivadas em outro assembly.

public class MyClass
{
    
    
    public int PublicMember;
    private int PrivateMember;
    protected int ProtectedMember;
    internal int InternalMember;
    protected internal int ProtectedInternalMember;
}

O que são construtores em C#?
Resposta
Um construtor é um método especial em uma classe que é chamado quando um objeto dessa classe é criado. Um construtor tem o mesmo nome de uma classe e não possui tipo de retorno explícito. Os construtores podem estar sobrecarregados, o que significa que pode haver vários construtores em uma classe com diferentes listas de parâmetros.

O construtor é usado para:

Inicialize o estado do objeto (defina valores padrão para propriedades, campos, etc.).
Aloque recursos, como memória ou conexões de rede.
Valide os parâmetros de entrada ou garanta que os objetos estejam em um estado consistente.
exemplo:

public class Person
{
    
    
    public string Name {
    
     get; set; }
    public int Age {
    
     get; set; }

    // Default constructor
    public Person()
    {
    
    
        Name = "Unknown";
        Age = 0;
    }

    // Parameterized constructor
    public Person(string name, int age)
    {
    
    
        Name = name;
        Age = age;
    }
}

// Usage:
Person person1 = new Person(); // Calls the default constructor
Person person2 = new Person("John", 25); // Calls the parameterized constructor

O que é um indexador em C#?
Resposta
Um indexador em C# é um membro de classe que permite acessar os elementos de um objeto usando notação de índice, semelhante à forma como você acessa elementos em uma matriz ou coleção. Os indexadores fornecem uma maneira mais intuitiva de interagir com os elementos armazenados em uma classe, especialmente se ela contiver uma coleção ou array.

Para definir um indexador, você precisa usar a palavra-chave this, o tipo de elemento que deseja acessar e implementar acessadores get e set para acessar e modificar o elemento subjacente.

Aqui está um exemplo de implementação de indexador para uma classe de coleção personalizada simples:

public class MyCollection
{
    
    
    private int[] items = new int[10];

    public int this[int index]
    {
    
    
        get
        {
    
    
            return items[index];
        }
        set
        {
    
    
            items[index] = value;
        }
    }
}

// Usage:
MyCollection collection = new MyCollection();
collection[0] = 42; // Uses the indexer's set accessor
int firstItem = collection[0]; // Uses the indexer's get accessor

Como criar tratamento de exceções personalizado em C#?
Resposta
Para criar tratamento de exceção personalizado em C#, você pode criar uma classe de exceção personalizada que herda da classe interna System.Exception ou de uma de suas classes derivadas. As exceções personalizadas são úteis quando as classes de exceção integradas não cobrem condições de erro específicas no seu aplicativo.

Aqui está um exemplo de uma classe de exceção personalizada:

public class CustomException : Exception
{
    
    
    public CustomException() : base()
    {
    
    
    }

    public CustomException(string message) : base(message)
    {
    
    
    }

    public CustomException(string message, Exception innerException) : base(message, innerException)
    {
    
    
    }
}

CustomException agora você pode lançar e capturar seu código:

try
{
    
    
    // Some code that might throw a CustomException
    throw new CustomException("This is a custom exception");
}
catch (CustomException ex)
{
    
    
    Console.WriteLine("Caught a CustomException: " + ex.Message);
}

Como evitar herança de classe em C#?
Resposta
Para evitar herança de classe em C#, você pode usar a palavra-chave selada ao declarar uma classe. Uma classe selada não pode ser herdada por nenhuma outra classe e tentar herdar de uma classe selada resultará em um erro em tempo de compilação.

public sealed class NonInheritableClass
{
    
    
    // Class implementation
}

// This will result in a compile-time error:
public class MyClass : NonInheritableClass
{
    
    
}

Qual é a diferença entre “const” e “readonly” em C#?
As respostas
const e readonly são usadas em C# para criar variáveis ​​que não podem ser alteradas após a atribuição, mas têm algumas diferenças:

const:
só ​​pode ser aplicado a campos, não a propriedades.
Deve ser atribuído um valor no momento da declaração.
O valor atribuído deve ser uma expressão constante que possa ser resolvida em tempo de compilação.
const são implicitamente estáticos, você não pode usar membros de instância para inicializá-los.

public class Constants
{
    
    
    public const double Pi = 3.14159;
}
readonly:

Pode ser aplicado a campos e propriedades.
Pode ser atribuído no momento da declaração ou dentro de um construtor.
O valor atribuído pode ser uma expressão constante ou uma expressão não constante que é resolvida em tempo de execução.
Um campo somente leitura pode ser um membro estático ou de instância, dependendo de suas necessidades.

public class ReadOnlyFields
{
    
    
    public readonly int InstanceField;
    public static readonly int StaticField;

    public ReadOnlyFields(int instanceValue, int staticValue)
    {
    
    
        InstanceField = instanceValue;
        StaticField = staticValue;
    }
}

Resumo das diferenças:

const é uma constante de tempo de compilação cujo valor não pode depender de uma condição de tempo de execução. readonly é uma constante de tempo de execução cujo valor pode ser determinado em tempo de execução.
Os campos const são implicitamente estáticos, enquanto os campos somente leitura podem ser membros estáticos ou membros de instância.
O que é coleta de lixo em C#?
Resposta
A coleta de lixo (GC) em C# é um sistema automático de gerenciamento de memória fornecido pelo .NET Framework. É responsável por liberar memória que não é mais utilizada pela aplicação. O coletor de lixo rastreia objetos alocados no heap, determina quais objetos não estão mais acessíveis e recupera o espaço de memória correspondente.

Os principais benefícios da coleta de lixo são:

Melhora a produtividade do desenvolvedor reduzindo o código padrão para gerenciamento manual de memória.
Evita vazamentos de memória, pois a memória não utilizada é recuperada automaticamente.
Protege contra certos erros de programação, como ponteiros pendentes ou problemas de folga dupla.
A coleta de lixo do C# não é determinística, o que significa que você não pode prever exatamente quando o coletor de lixo será executado. Ele usa uma abordagem geracional onde os objetos são divididos em gerações para reduzir o tempo e os recursos gastos na coleta de lixo. O coletor de lixo normalmente é executado quando a memória disponível fica baixa ou quando o sistema está ocioso.

Embora a coleta de lixo possa trazer benefícios, ainda deve-se tomar cuidado ao lidar com objetos que consomem muitos recursos, como manipuladores de arquivos ou conexões de banco de dados. As classes que lidam com esse gerenciamento de recursos devem implementar a interface IDisposable para permitir a liberação determinística de recursos.

Descreve a programação orientada a objetos (OOP) em C#. Cite os principais conceitos de OOP.
Resposta A
programação orientada a objetos (OOP) é ​​um paradigma de programação que representa conceitos como objetos com propriedades (campos ou atributos) e comportamento (métodos). O objetivo da OOP é produzir código reutilizável, sustentável e modular, enfatizando a separação de interesses e aderindo aos princípios da OOP.

C# é uma linguagem de programação orientada a objetos que oferece suporte total aos conceitos de OOP. Os principais conceitos de OOP em C# são:

Encapsulamento: O processo de agrupar dados (propriedades) e métodos (funções) que operam nos dados em uma única unidade (classe). O encapsulamento ajuda a proteger o estado interno de um objeto e controla o acesso às suas propriedades.
Base de herança: A capacidade de uma classe herdar propriedades, métodos e comportamentos de outra classe para permitir a reutilização de código e representar uma hierarquia de objetos relacionados. Em C#, uma classe só pode herdar de uma classe, mas pode implementar várias interfaces.
Polimorfismo: Polimorfismo é a capacidade de uma única interface representar diferentes tipos ou métodos para ter múltiplas implementações baseadas em tipos derivados. Em C#, o polimorfismo pode ser alcançado por meio de sobrecarga (usando o mesmo nome de método e parâmetros diferentes no mesmo tipo) e substituição (redefinindo um método de classe base em uma classe derivada).
Abstração: Abstração é o processo de simplificar objetos e conceitos complexos do mundo real, concentrando-se em suas características essenciais. Em C#, a abstração é obtida usando classes e interfaces abstratas para definir um conjunto de propriedades e métodos públicos que os tipos relacionados devem implementar.
Como criar classe ou método genérico em C#?
Resposta
Uma classe ou método genérico em C# é aquele que pode usar qualquer tipo sem conversão explícita de tipo ou verificação de tipo em tempo de execução. Os tipos genéricos aumentam a reutilização, flexibilidade e segurança de tipo do código.

Para criar uma classe ou método genérico em C#, você precisa usar colchetes angulares para definir parâmetros de tipo. Aqui está um exemplo de uma classe genérica e um método genérico:

// A generic class example
public class GenericList<T>
{
    
    
    // Class implementation using the generic type parameter T
}

// A generic method example
public static T Max<T>(T value1, T value2) where T : IComparable<T>
{
    
    
    return value1.CompareTo(value2) > 0 ? value1 : value2;
}

Neste exemplo, T é o parâmetro de tipo da classe genérica GenericList e do método genérico Max(T, T). O método também usa uma restrição (onde T: IComparable) para garantir que o parâmetro de tipo T implemente a interface IComparable.

Qual é a diferença entre uma classe abstrata e uma interface em C#?
Resposta
Tanto as classes abstratas quanto as interfaces em C# são usadas para definir entidades abstratas, mas têm algumas diferenças:

Classe abstrata:

É possível ter métodos abstratos e não abstratos (implementação).
Pode haver campos (variáveis), propriedades e eventos.
Construtores e destruidores são suportados.
Pode ter modificadores de acesso (público, protegido, interno, etc.) para membros.
A herança é suportada; uma classe só pode herdar de uma classe abstrata.
Pode haver implementações completas para alguns métodos ou propriedades, mas eles não podem ser instanciados diretamente.
interface:

Só pode ter assinaturas de métodos, propriedades e eventos (sem implementação).
Não pode ter campos ou construtores.
Nenhum membro (método, propriedade, evento) pode ter um modificador de acesso (todos os membros são implicitamente públicos).
Herança múltipla é suportada; uma classe pode implementar múltiplas interfaces.
Não pode haver detalhes de implementação, apenas a assinatura do membro.
Em resumo, uma classe abstrata fornece uma implementação básica que pode ser compartilhada entre múltiplas classes derivadas, enquanto uma interface define um contrato que qualquer classe de implementação deve cumprir. Use classes abstratas quando quiser fornecer algum comportamento padrão, use interfaces quando precisar de herança múltipla ou quiser definir estritamente um contrato funcional comum.

Qual é a diferença entre os parâmetros “out” e “ref” em C#?
Responda
tanto ref quanto parâmetros em outC# são usados ​​para passar parâmetros por referência, permitindo que o método modifique o valor da variável passada fora do método. No entanto, existem algumas diferenças entre os dois:

referência:

Uma variável ref passada como argumento deve ser inicializada antes de ser passada para o método.
O método chamado não precisa atribuir um valor ao parâmetro ref porque já possui um valor. exemplo:

  public void Swap(ref int a, ref int b)
  {
    
    
      int temp = a;
      a = b;
      b = temp;
  }

  int x = 1, y = 2;
  Swap(ref x, ref y); // x = 2, y = 1 after the method call

saída:

A variável passada como parâmetro não precisa ser inicializada antes de ser passada para o método.
O método chamado deve atribuir valores aos parâmetros antes que o método retorne. exemplo:

  public void Divide(int a, int b, out int quotient, out int remainder)
  {
    
    
      quotient = a / b;
      remainder = a % b;
  }

  int q, r;
  Divide(10, 3, out q, out r); // q = 3, r = 1 after the method call

Em resumo, use parâmetros ref quando desejar que o método chamado modifique uma variável já inicializada e use parâmetros out quando desejar que o método chamado forneça um valor que não dependa do valor inicial da variável passada.

Descreve o conceito de delegação em C#.
Resposta
Um delegado em C# é um tipo de referência que representa um método com uma assinatura específica. Os delegados permitem tratar métodos como objetos e passá-los como parâmetros, retorná-los de métodos ou armazená-los como propriedades. Os delegados fornecem uma maneira de criar ponteiros de função ou retornos de chamada, possibilitando o desenvolvimento de aplicações mais flexíveis e extensíveis.

Os delegados são especialmente úteis ao projetar sistemas orientados a eventos, onde os componentes devem reagir a outros eventos ou sinais de componentes sem acoplamento rígido. A seguir está um exemplo de declaração, instanciação e invocação de delegado:

// Declare a delegate type with a specific signature
public delegate void MyDelegate(string message);

// A method that matches the delegate signature
public static void Greet(string message)
{
    
    
    Console.WriteLine("Hello, " + message);
}

// Create an instance of the delegate, assigning the method to it
MyDelegate greetDelegate = new MyDelegate(Greet);

// Invoke the delegate
greetDelegate("World");

C# também dá suporte a delegados genéricos, delegados multicast e delegados internos Func<T, TResult> e delegados Action (introduzidos no .NET Framework 3.5) para maior flexibilidade e usabilidade.

Métodos ", "Equals" e "ReferenceEquals"?
Resposta
em C#, "
", "Equals" e "ReferenceEquals" são usados ​​para comparar objetos ou valores quanto à igualdade, mas existem algumas diferenças:

== operador: ""O operador compara dois objetos ou valores quanto à igualdade. Para tipos de valor, ele verifica a igualdade de valores. Para tipos de referência, ele verifica a igualdade de referências de objetos, o que significa que elas apontam para o mesmo objeto na memória. Para tipos de referência personalizados, pode estar sobrecarregado por ""para substituir esse comportamento.

   int a = 10;
   int b = 10;
   Console.WriteLine(a == b); // True, because the values are equal

   string s1 = "hello";
   string s2 = new String("hello".ToCharArray());

Console.WriteLine(s1 == s2); // Falso, porque as referências do objeto são diferentes
Equals: O método "Equals" compara dois objetos quanto à igualdade, verificando seus valores em vez de suas referências. A implementação padrão de "Equals" para tipos de referência verifica a igualdade de referência, mas pode ser substituída em classes personalizadas para fornecer comparações baseadas em valores.

   string s1 = "hello";
   string s2 = new String("hello".ToCharArray());
   Console.WriteLine(s1.Equals(s2)); // True, because the values are equal

ReferenceEquals: O método "ReferenceEquals" verifica se duas referências de objetos são iguais, o que significa que apontam para o mesmo objeto na memória. Não compara valores. Este método não pode ser substituído e é útil quando é necessário realizar comparações de referência estritas.

   string s1 = "hello";
   string s2 = new String("hello".ToCharArray());
   Console.WriteLine(ReferenceEquals(s1, s2)); // False, because the object references are different

Em resumo, use o operador "==" para comparações simples de valores e comparações de referência, use "Equals" quando precisar realizar comparações baseadas em valores em tipos de referência e use "ReferenceEquals" quando precisar comparar referências de objetos especificamente.

Explica o conceito de injeção de dependência em C#.
Resposta
Dependency Injection (DI) é um padrão de design usado em C# e outras linguagens orientadas a objetos que ajuda a separar a criação e o gerenciamento de dependências de objetos, melhorando assim a modularidade, a capacidade de manutenção e a testabilidade dos aplicativos.

No contexto do C#, a injeção de dependência é uma técnica na qual um objeto recebe suas dependências (os objetos, serviços ou valores dos quais depende) de uma fonte externa, em vez de criar, gerenciar ou localizar essas dependências diretamente. A injeção de dependência pode ser implementada usando injeção de construtor, injeção de propriedade ou injeção de método:

Injeção de construtor: as dependências são passadas para um objeto por meio de seu construtor. Esta é a abordagem mais comum e recomendada para injeção de dependência, pois garante que o objeto seja criado com todas as dependências necessárias e esteja em um estado válido.

   public class UserService
   {
    
    
       private readonly ILogger _logger;

       public UserService(ILogger logger)
       {
    
    
           _logger = logger;
       }

       public void DoSomething()
       {
    
    
           _logger.Log("User Service is doing something.");
       }
   }

Injeção de propriedade: as dependências são definidas por meio de propriedades públicas ou configuradores de objetos. Use esta técnica quando as dependências forem opcionais ou puderem mudar durante a vida útil do objeto.

   public class UserService
   {
    
    
       public ILogger Logger {
    
     get; set; }

       public void DoSomething()
       {
    
    
           Logger?.Log("User Service is doing something.");
       }
   }

Injeção de método: as dependências são passadas aos objetos por meio de métodos. Esta técnica é adequada quando um objeto requer apenas um método e não uma dependência específica durante todo o tempo de vida do objeto.

   public class UserService
   {
    
    
       public void DoSomething(ILogger logger)
       {
    
    
           logger.Log("User Service is doing something.");
       }
   }

Em C#, estruturas populares de injeção de dependência, como Autofac, Unity ou a injeção de dependência integrada do .NET Core, podem ser usadas para gerenciar e resolver dependências de objetos.

Como o C# suporta herança múltipla?
Resposta
C# não oferece suporte direto à herança múltipla de classes. As classes em C# só podem herdar de uma classe base. Porém, C# permite herança múltipla através de interfaces, uma vez que uma classe pode implementar mais de uma interface.

Quando uma classe implementa múltiplas interfaces, ela essencialmente herda o comportamento de cada interface, e cada interface pode ser considerada como um contrato que a classe deve cumprir. Essa abordagem para herança múltipla oferece flexibilidade, evitando as complexidades e ambiguidades que a herança de múltiplas classes pode criar.

exemplo:

public interface IEngine
{
    
    
    void StartEngine();
}

public interface IDriver
{
    
    
    void Drive();
}

public class Car : IEngine, IDriver
{
    
    
    public void StartEngine()
    {
    
    
        Console.WriteLine("Car engine started.");
    }

    public void Drive()
    {
    
    
        Console.WriteLine("Car is being driven.");
    }
}

// Usage:
Car car = new Car();
car.StartEngine();
car.Drive();

Neste exemplo, Car implementa as interfaces IEngine e IDriver para fornecer múltiplas funcionalidades semelhantes a herança.

O que é sobrecarga de método em C#?
Resposta
A sobrecarga de método é um recurso do C# que permite que uma classe tenha vários métodos com o mesmo nome, mas listas de parâmetros diferentes. O método correto é chamado em tempo de compilação com base nos argumentos fornecidos. A sobrecarga de método é uma forma de obter polimorfismo em tempo de compilação. O tipo de retorno do método não leva em consideração a sobrecarga. Assinaturas de métodos, ou seja, nomes de métodos e listas de parâmetros devem ser exclusivos.

Aqui está um exemplo:

public class Calculator
{
    
    
    public int Add(int x, int y)
    {
    
    
        return x + y;
    }

    public double Add(double x, double y)
    {
    
    
        return x + y;
    }

    public int Add(int x, int y, int z)
    {
    
    
        return x + y + z;
    }
}

No exemplo acima, sobrecarregamos o método Add com uma lista de parâmetros diferente.

É isso, pessoal! Essas 20 perguntas para iniciantes em C# são apenas o começo.

Fique ligado comigo enquanto compartilho mais perguntas de entrevistas em C# para todos os níveis de habilidade, do novato ao profissional experiente.

Não esqueça de seguir para se manter informado. Vamos para C# juntos!

Acho que você gosta

Origin blog.csdn.net/qq_52010446/article/details/131426312
Recomendado
Clasificación