문제

직장에서 저는 특정 개체의 수많은 속성을 구성하는 동안 또는 수명 초기에 설정해야 하는 프로젝트를 자주 수행합니다.편의성과 가독성을 위해 저는 다음을 자주 사용합니다. 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 UserHandler.GetUser.First.User
    .FirstName="Stefan"
    .LastName="Karlsson"
    .Age="39"
    .Sex="Male"
    .Occupation="Programmer"
    .UserID="0"
end 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 구조는 나쁘다.

.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

분해는 다음과 같습니다. sb2'에스 Append 방법과 동일하게 보입니다 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

그러므로 당신이 그것을 좋아하고 더 읽기 쉬운 것을 찾으십시오. 설득력있는 이유는 없습니다.

(그런데, , 나는 디버거에서 무슨 일이 있었는지 알고 싶어합니다. With 진술, 그래서 나는 당신이 어떤 행동을 보았는지 궁금합니다.)

물체를 사용하고 반복적으로 언급하는 것에는 차이가 있습니다. 이는 미묘하지만 염두에 두어야한다고 생각합니다.

with 문을 사용하면 객체를 참조하는 새로운 로컬 변수를 만듭니다. .xx를 사용한 후속 참조는 해당 로컬 참조의 속성에 대한 참조입니다. with 명령문을 실행하는 동안 원래 변수 참조가 변경되면 With가 참조한 객체는 변경되지 않습니다. 고려하다:

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

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

따라서, 진술은 단순히 구문 설탕이 아니라 진정으로 다른 구성입니다. 위와 같이 명시적인 것을 코딩 할 가능성은 거의 없지만 어떤 상황에서는 부주의하게 발생할 수 있으므로 문제를 알고 있어야합니다. 가장 가능성이 높은 상황은 속성을 설정하여 내 상호 연결을 암시 적으로 변경하는 객체 네트워크와 같은 구조를 가로 지르는 곳입니다.

그것은 모두 가독성에 관한 것입니다. 모든 구문 설탕과 마찬가지로 가능합니다 과도하게 사용되었습니다.

만약 그것을 받아들이십시오 몇 줄에 객체의 여러 멤버를 설정하고 있습니다.

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

피하다 "with"로 다른 일을

50-100 줄에 걸쳐 블록을 사용하고 다른 많은 변수가 포함 된 경우 블록 상단에서 선언 된 내용을 기억하기가 어려울 수 있습니다. 명백한 이유로, 나는 그러한 지저분한 코드의 예를 제공하지 않을 것입니다.

코드를 진정으로 읽기 쉽게 만드는 곳에서는 가십시오. 그것이 어디에 있는지 더 적은 읽을 수 있고, 피하십시오 - 특히, 나는 당신이 진술과 함께 둥지를 피우는 것을 제안하는 것이 좋습니다.

C# 3.0에는 객체 초기화를위한이 기능이 있습니다.

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

이것은 LINQ에 거의 필요할뿐만 아니라 구문이 코드 냄새를 나타내지 않는 위치에서도 의미가 있습니다. 나는 일반적으로 초기 구성을 넘어서 객체에서 다양한 작업을 수행 할 때 해당 작업이 객체 자체의 단일 작업으로 캡슐화되어야한다는 것을 알게됩니다.

당신의 예에 대한 한 가지 메모 - 당신은 정말로 "나"가 필요합니까? 그냥 쓰지 않는 이유 :

PropertyA = True
PropertyB = "Inactive"

? 그 경우에 분명히 "나"가 암시된다 ...

이 키워드를 많이 사용하는 코드를 의심 할 것입니다. 인스턴스 변수 또는 속성을 쉽게 설정하는 데 사용되면 클래스가 너무 클 수 있다고 생각합니다 (클래스가 너무 커질 수 있습니다). 큰 수업 냄새 ). 이와 같이 긴 통화 사슬을 교체하는 데 사용하는 경우 :

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"

그러면 당신은 아마도 위반하고있을 것입니다 Demeter Law

나는 vb.net을 사용하지 않습니다 (평범한 VB를 사용 했음).

주요 도트는 필수입니까? 그렇다면 문제가 보이지 않습니다. JavaScript에서 사용 결과 with 객체의 속성은 일반 변수와 동일하게 보이며 저것 속성이나 변수에 액세스하는지 알 수 없으므로 매우 위험합니다. with 피해야 할 것입니다.

눈에는 사용이 더 쉬울뿐만 아니라 물체의 특성에 대한 반복적 인 액세스를 위해서는 메소드 체인을 통해 한 번만 메소드 체인을 통해 모든 속성에 대해 한 번만 가져 오기 때문에 더 빠를 수 있습니다.

나는 당신이 중첩 된 사용을 피해야한다는 다른 대답에 동의합니다. with, 피해야하는 이유와 같은 이유로 with JavaScript에서 모두 : 당신은 더 이상 당신의 재산이 속하는 객체를 보지 않기 때문입니다.

'With'는 기본적으로 Smalltalk의 '캐스케이드'입니다. Kent Beck의 Smalltalk 모범 사례 패턴 책의 패턴입니다.

패턴 요약 : 객체에 전송 된 메시지를 그룹화하는 것이 합리적 일 때 사용하십시오. 동일한 객체로 전송 된 메시지 일 경우 사용하지 마십시오.

피하십시오 블록으로 반드시 (심지어 가독성). 두 가지 이유 :

  1. 그만큼 with with에 대한 Microsoft 문서 어떤 상황에서는 스택에 데이터 사본을 생성하므로 변경 사항이 버려집니다.
  2. LINQ 쿼리에 사용하면 Lambda 결과는 체인되지 않으므로 각 중간 절의 결과가 버려집니다.

이것을 설명하기 위해, 우리는 저의 동료에게 저자에게 물어봐야 할 교과서의 예를 가지고 있습니다 (실제로 부정확합니다. 이름이 보호하기 위해 변경되었습니다 ... 무엇이든).

dbcontext.blahs와 함께
.Orderby (function (currentBlah) currentBlah.lastName)
.thenby (function (currentblah) currentblah.firstname)
.짐()
끝납니다

Orderby와 그때는 가지고 있습니다 효과가 없습니다 조금도. With를 삭제하고 끝나고 처음 세 줄의 끝에 라인 연속 문자를 추가하여 코드를 재구성하는 경우 ... 작동합니다. 15 페이지 후 같은 교과서에서).

우리는 더 이상 이유가 필요하지 않습니다 찾아서 파괴해라 블록으로. 그들은 단지 의미가있었습니다 해석 뼈대.

구조와 함께 사용할 때 문제가 있습니다. 즉, "with" 표현식의 로컬 복사본(with 블록에 입력할 때 만들어짐)에서 작업하고 있고 (복사본으로 작업하지 않기 때문에 해당 필드를 설정할 수 없습니다) an) 이 경우 객체 참조:

객체 표현의 데이터 유형은 클래스 또는 구조 유형 또는 정수와 같은 시각적 기본 기본 유형 일 수 있습니다.ObjectExpression이 객체 이외의 다른 것으로 발생하면 멤버의 값 만 읽거나 메소드를 호출 할 수 있으며, with ... with 명령문에 사용 된 구조의 값에 값을 할당하려고하면 오류가 발생합니다.구조를 반환하고 getApoint (). x = 1과 같은 함수 결과의 구성원에게 즉시 액세스하고 값을 할당 한 메소드를 호출 한 경우에 동일한 오류입니다.두 경우 모두 문제는 구조가 통화 스택에만 존재한다는 것입니다. 이러한 상황에서 수정 된 구조 구성원이 프로그램의 다른 코드가 변경을 관찰 할 수 있도록 위치에 쓸 수있는 방법이 없다는 것입니다.

objectExpression은 블록에 들어갈 때 한 번 평가됩니다.With Block 내에서 Objectexpression을 재 할당 할 수 없습니다.

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

with 문에 구조를 반환하는 표현식 대신 구조 이름을 전달하면 컴파일러가 좀 더 영리했을 것 같지만 그렇지 않은 것 같습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top