IT Share you

VB.NET 'With'진술-포용 또는 피?

shareyou 2020. 11. 7. 17:54
반응형

VB.NET 'With'진술-포용 또는 피?


직장에서 저는 특정 개체의 수많은 속성을 구성 중이나 수명 초기에 설정해야하는 프로젝트를 자주 작업합니다. 편의성과 가독성을 위해 With이러한 속성을 설정하는 데 종종 문을 사용합니다 . 나는 그것을 발견

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

보다 훨씬 좋아 보인다

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

단순히 속성을 설정하는 매우 긴 문에 사용됩니다.

With디버깅 하는 동안 사용 하는 데 몇 가지 문제가 있음을 발견했습니다 . 그러나 실제로 사용하지 않아야하는 설득력있는 이유가 있는지 궁금합니다With . 위의 두 가지 경우에 대해 컴파일러를 통해 생성 된 코드가 기본적으로 동일하다고 항상 가정 해 왔기 때문에 항상 더 읽기 쉽게 작성하도록 선택했습니다.


긴 변수 이름이 있고 다음과 같이 끝날 경우 :

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

그런 다음 WITH를 사용하여 더 읽기 쉽게 만들 것입니다.

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

이후 예제에서는 첫 번째 예제에서 사용자 속성에 액세스 할 때마다 사용자를 가져오고 WITH의 경우 사용자를 한 번만 가져 오기 때문에 첫 번째 예제보다 성능상의 이점이 있습니다.

다음과 같이 with를 사용하지 않고도 성능 향상을 얻을 수 있습니다.

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"

그러나 대신 WITH 문을 사용하겠습니다.

그리고 나는 이것을 예제로 삼았으므로 키워드가 많은 클래스에 대해 불평하지 마십시오. 다른 예제는 다음과 같습니다. WITH RefundDialog.RefundDatagridView.SelectedRows (0)


실제로, 그것에 대해 정말로 설득력있는 요점이 없습니다. 나는 팬은 아니지만 그것은 개인적인 선호도이며 With구조가 나쁘다는 것을 암시하는 경험적 데이터가 없습니다 .

.NET에서는 개체 이름을 정규화하는 것과 정확히 동일한 코드로 컴파일되므로이 설탕에 대한 성능 저하가 없습니다. 다음 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

디스 어셈블리는 다음과 같습니다. sb2Append메서드에 With대한 호출은 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

그래서 당신이 그것을 좋아하고 더 읽기 쉽다고 생각한다면, 그것을 위해 가십시오; 그렇게하지 않을 설득력있는 이유가 없습니다.

(그런데 Tom , 저는 디버거에서 무슨 일이 일어 났는지 알고 싶습니다. With진술을 기반으로 디버거에서 비정상적인 동작을 본 적이 없었기 때문에 어떤 동작을 보았는지 궁금합니다. .)


There is a difference between using With and making repeating references to an object, which is subtle but should be borne in mind, I think.

When a WITH statement is used, it creates a new local variable referencing the object. Subsequent references using .xx are references to properties of that local reference. If during the execution of the WITH statement, the original variable reference is changed, the object referenced by the WITH does not change. Consider:

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

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

So, the WITH statement is not simply syntactical sugar, it is genuinely a different construct. Whilst you would be unlikely to code something explicit like the above, in some situations this might occur inadvertently so you should be aware of the issue. The most likely situation is where you may be traversing a structure such as a network of objects whose interconnections my be implicitly changed by setting properties.


It's all about readability. Like all syntactic sugar, it can be overused.

Embrace it IF you're setting several members of an object over a few lines

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

Avoid doing anything else with "With"

If you write a With block that spans 50-100 lines and involves lots of other variables it can make it REALLY difficult to remember what was declared at the top of the block. For obvious reasons, I won't provide an example of such messy code


Where it makes the code genuinely more readable, go for it. Where it makes it less readable, avoid it - in particular, I suggest you avoid nesting With statements.

C# 3.0 has this feature solely for object initialization:

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

This is not only pretty much required for LINQ, but it also makes sense in terms of where the syntax doesn't indicate a code smell. I usually find that when I'm performing many different operations on an object beyond its initial construction, those operations should be encapsulated as a single one on the object itself.

One note about your example - do you really need the "Me" at all? Why not just write:

PropertyA = True
PropertyB = "Inactive"

? Surely "Me" is implied in that case...


I would be suspicious of code that uses a lot this keyword: if it is used to make easier to set lots of instance variables or properties I think this may indicate that your classes are too large ( Large Class smell ). If you use it to replace long chains of calls like this:

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"

then you are probably violating Demeter Law


I don't use VB.NET (I used to use plain VB) but...

Is the leading dot mandatory? If so, then I don't see a problem. In Javascript, the result of using with is that a property of an object looks just the same as a plain variable, and that is very dangerous, as you don't see if you're accessing a property or a variable, and thus, with is something to avoid.

Not only is its use easier on the eyes, but for repeated access to properties of an object, it's likely to be faster, as the object is fetched through the method chain only once, and not once for every property.

I do agree with other replies that you ought to avoid nested use of with, for the same reason as why to avoid with altogether in Javascript: because you no longer see what object your property belongs to.


The 'with' is basically the 'cascade' from Smalltalk. It is a pattern in Kent Beck's Smalltalk Best Practice Patterns book.

A summary of the pattern: use it when it makes sense to group the messages sent to the object. Don't use it if it just happens to be some messages sent to the same object.


AVOID the WITH Block at all costs (even readability). Two reasons:

  1. the Microsoft Documentation about With...End With says that in some circumstances, it creates a copy of the data on the stack, so any changes that you make will be thrown away.
  2. If you use it for LINQ Queries, the lambda results DO NOT Chain and so each intermediate clause's result is thrown away.

To describe this, we have a (broken) example from a Textbook that my co-worker had to ask the author about (it is indeed incorrect, the Names have been changed to protect... whatever):

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

The OrderBy and ThenBy have No Effect at all. IF you reformat the code by ONLY dropping the With and End With, and adding line continuation characters at the end of the first three lines... it works (as shown 15 pages later in the same textbook).

We don't need any more reason to search and destroy WITH Blocks. They only had meaning in an Interpreted framework.


There's a gotcha when using it with structures, aka you can't set their fields, since you're working on a local copy (made at time of entry in with block) of the "with" expression and not working with a (copy of an) object reference in that case:

The data type of objectExpression can be any class or structure type or even a Visual Basic elementary type such as Integer. If objectExpression results in anything other than an object, you can only read the values of its members or invoke methods, and you get an error if you try to assign values to members of a structure used in a With...End With statement. This is the same error you would get if you invoked a method that returned a structure and immediately accessed and assigned a value to a member of the function’s result, such as GetAPoint().x = 1. The problem in both cases is that the structure exists only on the call stack, and there is no way a modified structure member in these situations can write to a location such that any other code in the program can observe the change.

The objectExpression is evaluated once, upon entry into the block. You can't reassign the objectExpression from within the With block.

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

guess the compiler could have been a bit more clever if you pass to with statement a structure name instead of an expression that returns a structure, but seems it's not

참고URL : https://stackoverflow.com/questions/283749/the-vb-net-with-statement-embrace-or-avoid

반응형