Em Java e C #, é possível criar um objeto com propriedades que podem ser configuradas na inicialização, definindo um construtor com parâmetros, definindo cada propriedade após a construção do objeto ou usando o padrão de interface do construtor / fluido. No entanto, o C # 3 introduziu inicializadores de objetos e coleções, o que significava que o padrão do construtor era praticamente inútil. Em uma linguagem sem inicializadores, pode-se implementar um construtor e usá-lo da seguinte maneira:
Vehicle v = new Vehicle.Builder()
.manufacturer("Toyota")
.model("Camry")
.year(1997)
.colour(CarColours.Red)
.addSpecialFeature(new Feature.CDPlayer())
.addSpecialFeature(new Feature.SeatWarmer(4))
.build();
Por outro lado, em C #, pode-se escrever:
var vehicle = new Vehicle {
Manufacturer = "Toyota",
Model = "Camry",
Year = 1997,
Colour = CarColours.Red,
SpecialFeatures = new List<SpecialFeature> {
new Feature.CDPlayer(),
new Feature.SeatWarmer { Seats = 4 }
}
}
... eliminando a necessidade de um construtor, como visto no exemplo anterior.
Com base nesses exemplos, os construtores ainda são úteis em C # ou foram substituídos inteiramente pelos inicializadores?
c#
object-oriented
builder-pattern
svbnet
fonte
fonte
are builders useful
por que continuo vendo esse tipo de pergunta? Um Construtor é um padrão de design - com certeza, pode ser exposto como um recurso de linguagem, mas no final do dia é apenas um padrão de design. Um padrão de design não pode estar "errado". Pode ou não atender ao seu caso de uso, mas isso não faz com que todo o padrão esteja errado, apenas a aplicação dele. Lembre-se de que, no final do dia, os padrões de design resolvem problemas específicos - se você não enfrenta o problema, por que você tentaria resolvê-lo?Respostas:
Conforme abordado por @ user248215, o verdadeiro problema é imutabilidade. O motivo pelo qual você usaria um construtor em C # seria manter a testemunha explícita de um inicializador sem precisar expor propriedades configuráveis. Não é uma questão de encapsulamento e é por isso que escrevi minha própria resposta. O encapsulamento é razoavelmente ortogonal, pois invocar um setter não implica o que o setter realmente faz ou o vincula à sua implementação.
A próxima versão do C #, 8.0, provavelmente introduzirá uma
with
palavra - chave que permitirá que objetos imutáveis sejam inicializados de forma clara e concisa, sem a necessidade de escrever construtores.Outra coisa interessante que você pode fazer com os construtores, ao contrário dos inicializadores, é que eles podem resultar em diferentes tipos de objetos, dependendo da sequência de métodos chamados.
Por exemplo
Apenas para esclarecer o exemplo acima, é uma biblioteca de correspondência de padrões que usa o padrão do construtor para criar uma "correspondência" especificando casos. Os casos são anexados chamando o
Case
método que passa por uma função. Sevalue
for atribuível ao tipo de parâmetro da função, é invocado. Você pode encontrar o código fonte completo no GitHub e, como os comentários XML são difíceis de ler em texto simples, aqui está um link para a documentação criada pelo SandCastle (consulte a seção Comentários )fonte
IEnumerable<Func<T, TResult>>
membro.TResult
. Em última análise, a inferência de tipo tinha muito a ver com isso. Eu também queria que "parecesse" uma estrutura de controle. Também não queria usar um inicializador, pois isso permitiria a mutação.Os inicializadores de objetos exigem que as propriedades sejam acessíveis pelo código de chamada. Construtores aninhados podem acessar membros privados da classe.
Se você quisesse tornar
Vehicle
imutável (via tornar todos os setters privados), o construtor aninhado poderia ser usado para definir as variáveis privadas.fonte
Todos eles servem a propósitos diferentes !!!
Os construtores podem inicializar campos marcados
readonly
, além de membros privados e protegidos. No entanto, você é um pouco limitado no que pode fazer dentro de um construtor; evite passarthis
para qualquer método externo, por exemplo, e evite chamar membros virtuais, pois eles podem ser executados no contexto de uma classe derivada que ainda não foi construída. Além disso, é garantido que os construtores são executados (a menos que o chamador esteja fazendo algo muito incomum); portanto, se você definir campos no construtor, o código no restante da classe poderá assumir que esses campos não serão nulos.Os inicializadores são executados após a construção. Eles apenas permitem que você chame propriedades públicas; campos privados e / ou somente leitura não podem ser definidos. Por convenção, o ato de estabelecer uma propriedade deve ser bastante limitado, por exemplo, deve ser idempotente e ter efeitos colaterais limitados.
Os métodos do construtor são métodos reais e, portanto, permitem mais de um argumento e, por convenção, podem ter efeitos colaterais, incluindo a criação de objetos. Embora não possam definir campos somente leitura, eles podem praticamente fazer qualquer outra coisa. Além disso, os métodos podem ser implementados como métodos de extensão (como praticamente toda a funcionalidade LINQ).
fonte