Pergunta

No trabalho, eu sou freqüentemente trabalhando em projetos onde inúmeras propriedades de certos objetos têm que ser definido durante a sua construção ou início durante sua vida. Por uma questão de conveniência e legibilidade, muitas vezes eu usar a instrução With definir essas propriedades. Acho que

With Me.Elements
    .PropertyA = True
    .PropertyB = "Inactive"
    ' And so on for several more lines
End With

Looks muito melhor do que

Me.Elements.PropertyA = True
Me.Elements.PropertyB = "Inactive"
' And so on for several more lines

para instruções muito longas que simplesmente definir propriedades.

Eu tenho notado que existem alguns problemas com o uso With durante a depuração; no entanto, Eu queria saber se havia quaisquer razões convincentes para evitar o uso With na prática ? Eu sempre assumiu o código gerado via o compilador para os dois casos acima é basicamente o mesmo que é por isso que eu sempre escolhido para escrever o que eu sinto para ser mais legível.

Foi útil?

Solução

Se você tem muito tempo variablenames e iria acabar com:

UserHandler.GetUser.First.User.FirstName="Stefan"
UserHandler.GetUser.First.User.LastName="Karlsson"
UserHandler.GetUser.First.User.Age="39"
UserHandler.GetUser.First.User.Sex="Male"
UserHandler.GetUser.First.User.Occupation="Programmer"
UserHandler.GetUser.First.User.UserID="0"
....and so on

então eu usaria COM para torná-lo mais legível:

With UserHandler.GetUser.First.User
    .FirstName="Stefan"
    .LastName="Karlsson"
    .Age="39"
    .Sex="Male"
    .Occupation="Programmer"
    .UserID="0"
end with

No exemplo mais tarde há benefício de desempenho, mesmo em relação ao primeiro exemplo, porque no primeiro exemplo Im buscar o usuário cada vez que acessar uma propriedade do usuário e no COM caso eu só buscar o usuário uma vez.

posso obter o ganho de desempenho sem usar com, como este:

dim myuser as user =UserHandler.GetUser.First.User
myuser.FirstName="Stefan"
myuser.LastName="Karlsson"
myuser.Age="39"
myuser.Sex="Male"
myuser.Occupation="Programmer"
myuser.UserID="0"

Mas eu iria para a instrução WITH vez, parece mais limpo.

E eu só tomou isso como um exemplo para que não faça reclamar sobre uma classe com muitas palavras-chave, outro exemplo poderia ser assim: COM RefundDialog.RefundDatagridView.SelectedRows (0)

Outras dicas

Na prática, não há pontos realmente imperiosas contra ele. Eu não sou um fã, mas que é uma preferência pessoal, não há dados empíricos que sugerem que a construção With é ruim.

Em .NET, ele compila a exatamente o mesmo código que totalmente qualificar o nome do objeto, de modo que não há nenhuma penalidade de desempenho para este açúcar. I verificado isto compilando, em seguida, desmontar, a seguinte classe VB .NET 2.0:

Imports System.Text

Public Class Class1
    Public Sub Foo()
        Dim sb As New StringBuilder
        With sb
            .Append("foo")
            .Append("bar")
            .Append("zap")
        End With

        Dim sb2 As New StringBuilder
        sb2.Append("foo")
        sb2.Append("bar")
        sb2.Append("zap")
    End Sub
End Class

A desmontagem é a seguinte - nota que as chamadas para olhar de método sb2 de Append idênticos aos apelos declaração With para sb:

.method public instance void  Foo() cil managed
{
  // Code size       91 (0x5b)
  .maxstack  2
  .locals init ([0] class [mscorlib]System.Text.StringBuilder sb,
           [1] class [mscorlib]System.Text.StringBuilder sb2,
           [2] class [mscorlib]System.Text.StringBuilder VB$t_ref$L0)
  IL_0000:  nop
  IL_0001:  newobj     instance void [mscorlib]System.Text.StringBuilder::.ctor()
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  stloc.2
  IL_0009:  ldloc.2
  IL_000a:  ldstr      "foo"
  IL_000f:  callvirt   instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string)
  IL_0014:  pop
  IL_0015:  ldloc.2
  IL_0016:  ldstr      "bar"
  IL_001b:  callvirt   instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string)
  IL_0020:  pop
  IL_0021:  ldloc.2
  IL_0022:  ldstr      "zap"
  IL_0027:  callvirt   instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string)
  IL_002c:  pop
  IL_002d:  ldnull
  IL_002e:  stloc.2
  IL_002f:  newobj     instance void [mscorlib]System.Text.StringBuilder::.ctor()
  IL_0034:  stloc.1
  IL_0035:  ldloc.1
  IL_0036:  ldstr      "foo"
  IL_003b:  callvirt   instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string)
  IL_0040:  pop
  IL_0041:  ldloc.1
  IL_0042:  ldstr      "bar"
  IL_0047:  callvirt   instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string)
  IL_004c:  pop
  IL_004d:  ldloc.1
  IL_004e:  ldstr      "zap"
  IL_0053:  callvirt   instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string)
  IL_0058:  pop
  IL_0059:  nop
  IL_005a:  ret
} // end of method Class1::Foo

Então, se você gosta, e encontrá-lo mais legível, vá para ele; não há nenhuma razão convincente para não.

(By the way, Tom , eu estou interessado em saber o que aconteceu com o depurador - eu posso' t lembro de ter visto qualquer comportamento incomum no depurador com base em uma declaração With, por isso estou curioso para saber o comportamento que você viu.)

Há uma diferença entre usar Com e fazendo referências repetindo a um objeto, que é sutil, mas deve-se ter em mente, eu acho.

Quando uma instrução WITH é usado, ele cria uma nova variável local referenciando o objeto. As referências subsequentes utilizando .xx são referências a propriedades de que a referência local. Se durante a execução da instrução WITH, a referência variável original for alterado, o objeto referenciado pelo COM não muda. Considere o seguinte:

Dim AA As AAClass = GetNextAAObject()
With AA
    AA = GetNextAAObject()

    '// Setting property of original AA instance, not later instance
    .SomeProperty = SomeValue
End With

Assim, a instrução WITH não é o açúcar simplesmente sintática, é realmente uma construção diferente. Enquanto você não seria susceptível de código algo explícito como o acima, em algumas situações isso pode ocorrer inadvertidamente, então você deve estar ciente do problema. A situação mais provável é que você pode estar atravessando uma estrutura tal como uma rede de objetos cujas interconexões Meu ser alterado implicitamente definindo propriedades.

É tudo sobre a legibilidade. Como todos os açúcar sintático, pode ser em demasia .

Abrace-o IF você está definindo vários membros de um objeto ao longo de algumas linhas

With myObject
  .Property1 = arg1
  .Property2 = arg2
...

Evite fazer qualquer outra coisa com "com"

Se você escreve um Com bloco que abrange 50-100 linhas e envolve muitas outras variáveis ??que podem torná-lo realmente difícil lembrar o que foi declarado no topo do bloco. Por razões óbvias, não vou dar um exemplo de tal código confuso

Onde torna o código mais legível realmente, ir para ele. Onde se torna menos legível, evitá-lo -., Em particular, eu sugiro que você evite nidificação Com declarações

C # 3.0 tem esse recurso unicamente para inicialização de objeto:

var x = new Whatever { PropertyA=true, PropertyB="Inactive" };

Isto não só é bastante necessário para LINQ, mas também faz sentido em termos de onde a sintaxe não indica um cheiro de código. Eu costumo achar que quando eu estou realizando muitas operações diferentes em um objeto além da sua construção inicial, essas operações devem ser encapsulados como um único sobre o objeto em si.

Uma nota sobre o seu exemplo - você realmente precisa o "Me" em tudo? Porque não basta escrever:

PropertyA = True
PropertyB = "Inactive"

? Certamente "Me" está implícito nesse caso ...

Eu seria suspeito de código que usa muito esta palavra-chave: se ele é usado para fazer mais fácil de lotes conjunto de variáveis ??de instância ou propriedades eu acho que isso pode indicar que suas aulas são muito grandes ( Grande cheiro Classe ). Se você usá-lo para substituir longas cadeias de chamadas assim:

UserHandler.GetUser.First.User.FirstName="Stefan"
UserHandler.GetUser.First.User.LastName="Karlsson"
UserHandler.GetUser.First.User.Age="39"
UserHandler.GetUser.First.User.Sex="Male"
UserHandler.GetUser.First.User.Occupation="Programmer"
UserHandler.GetUser.First.User.UserID="0"

então provavelmente você está violando Lei Demeter

Não uso VB.NET (Eu costumava usar o VB simples) mas ...

é o principal ponto obrigatório? Se assim for, então eu não vejo um problema. Em Javascript, o resultado do uso with é que uma propriedade de um objeto aparência da mesma forma como uma variável simples, e que é muito perigoso, porque você não ver se você está acessando uma propriedade ou uma variável e, portanto, with é algo a ser evitado.

Não é só o seu uso mais fácil sobre os olhos, mas para o acesso repetido para propriedades de um objeto, é provável que seja mais rápido, como o objeto é buscado através da cadeia método apenas uma vez, e não uma vez para cada propriedade.

Eu concordo com outras respostas que você deve evitar o uso de nested with, pela mesma razão como por que para evitar with totalmente em Javascript:., Porque você já não vê o objeto de sua propriedade pertence

A 'com' é basicamente a 'cascata' de Smalltalk. É um padrão em Smalltalk Best Practice Patterns livro de Kent Beck.

Um resumo do padrão: use-o quando faz sentido agrupar as mensagens enviadas para o objeto. Não usá-lo se ele só acontece de haver algumas mensagens enviadas para o mesmo objeto.

evitar o com bloco em todos os custos (mesmo legibilidade). Duas razões:

  1. Microsoft Documentação sobre With ... End With diz que em algumas circunstâncias, ele cria uma cópia dos dados na pilha, de modo que quaisquer alterações que você fizer vai ser jogado fora.
  2. Se você usá-lo para LINQ consultas, os resultados lambda não acorrentam e assim o resultado de cada cláusula intermediário é jogado fora.

Para descrever essa, temos um exemplo (quebrado) de um livro que meu co-trabalhador tinha de perguntar ao autor sobre (ele é realmente incorreta, os nomes foram alterados para proteger ... o que quer):

Com dbcontext.Blahs
.OrderBy (Function (currentBlah) currentBlah.LastName)
.ThenBy (Function (currentBlah) currentBlah.FirstName)
.Load ()
End With

O OrderBy e ThenBy Tem No Effect em tudo. Se reformatar o código apenas por deixar cair a Com e terminar com, e adicionando caracteres de continuação de linha no final das três primeiras linhas ... ele funciona (como mostrado 15 páginas depois no mesmo livro) .

Não precisamos mais razão para procurar e destruir com blocos. Eles só tinham significado em um Interpretada quadro.

Há uma pegadinha quando usá-lo com estruturas, aka não é possível definir seus campos, desde que você está trabalhando em uma cópia local (feita no momento da entrada no com bloco) do "com" expressão e não trabalhar com uma (cópia de um) referência de objeto, nesse caso:

O tipo de dados objectExpression pode ser qualquer classe ou estrutura tipo ou mesmo um tipo elementar Visual Basic, como Integer. E se objectExpression resulta em qualquer coisa diferente de um objeto, você pode somente leitura dos valores de seus membros ou métodos de invocação, e você terá uma de erro se você tentar valores atribuir a membros de uma estrutura usados ??em uma With ... End With comunicado. Este é o mesmo erro que você obteria se chamado um método que voltou uma estrutura e imediatamente acedida e atribuído um valor a um membro do resultado da função, tais como GetAPoint (). X = 1. O problema em ambos os casos é que a estrutura só existe na pilha de chamadas, e não há nenhuma maneira um modificado membro da estrutura nestas situações pode escrever para uma localização tal que qualquer outro código no programa pode observar a mudança.

O objectExpression é avaliada uma vez, aquando da entrada no bloco. Vocês não pode transferir o objectExpression de dentro do Com bloco.

https : //docs.microsoft.com/en-us/dotnet/visual-basic/language-reference/statements/with-end-with-statement

acho que o compilador poderia ter sido um pouco mais inteligente se você passar para com a declaração de um nome de estrutura em vez de uma expressão que retorna uma estrutura, mas parece que não é

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top