나는 몇 가지 코드를 발견했다.
public int MaxHealth =>
Memory[Address].IsValid ?
Memory[Address].Read<int>(Offs.Life.MaxHp) :
0;
이제 나는 Lambda 표현에 어느 정도 익숙합니다. 나는 그것이 이런 식으로 사용되는 것을 보지 못했습니다.
위의 진술과 차이점은 무엇입니까?
public int MaxHealth = x ? y:z;
답변
당신이보고있는 것은 람다식이 아닌 식 본문 멤버 입니다.
컴파일러가 식 본문 속성 멤버를 만나면 본질적으로 다음과 같이 getter로 변환합니다.
public int MaxHealth
{
get
{
return Memory[Address].IsValid ? Memory[Address].Read<int>(Offs.Life.MaxHp) : 0;
}
}
(코드를 TryRoslyn 이라는 도구로 펌핑하여 직접 확인할 수 있습니다 .)
대부분의 C # 6 기능과 마찬가지로 표현 본문 멤버는 구문 설탕 일뿐 입니다. 이는 기존 기능으로는 달성 할 수없는 기능을 제공하지 않음을 의미합니다. 대신 이러한 새로운 기능을 통해보다 표현적이고 간결한 구문을 사용할 수 있습니다.
보다시피 표현형 멤버에는 속성 멤버를보다 간결하게 만드는 몇 가지 단축키가 있습니다.
return
컴파일러는 표현식의 결과를 리턴하려는 것으로 유추 할 수 있으므로 명령문 을 사용할 필요가 없습니다.- 본문은 하나의 표현식이므로 명령문 블록을 작성할 필요가 없습니다.
get
키워드는 표현식 본문 멤버 구문의 사용으로 암시되므로 키워드 를 사용할 필요가 없습니다 .
마지막 질문은 실제 질문과 관련이 있으므로 굵게 표시했습니다. 지금 답변하겠습니다.
차이점은 …
// expression-bodied member property
public int MaxHealth => x ? y:z;
과…
// field with field initializer
public int MaxHealth = x ? y:z;
의 차이점과 동일합니다 …
public int MaxHealth
{
get
{
return x ? y:z;
}
}
과…
public int MaxHealth = x ? y:z;
속성을 이해한다면 어느 것이 명백해야합니다.
그러나 첫 번째 리스팅은 액세스 할 때마다 호출되는 getter가있는 자산입니다. 두 번째 목록은 유형이 인스턴스화 될 때 표현식이 한 번만 평가되는 필드 이니셜 라이저가있는 필드입니다.
구문의 이러한 차이는 실제로 매우 미묘하며 “AC # 6 gotcha : Initialization vs. Expression Bodied Members” 라는 제목의 게시물에서 Bill Wagner가 설명하는 “gotcha”로 이어질 수 있습니다 .
표현 바디 회원 람다 expression- 동안 같은 , 그들이 있습니다 하지 람다 식입니다. 근본적인 차이점은 람다식이 델리게이트 인스턴스 또는 식 트리를 생성한다는 것입니다. Expression-bodyed 멤버는 배후에서 속성을 생성하기위한 컴파일러의 지시문 일뿐입니다. 유사성 (더 많거나 적은)은 화살표 ( =>
)로 시작하고 끝납니다 .
또한 표현형 멤버는 속성 멤버로 제한되지 않는다고 덧붙입니다. 그들은이 모든 멤버들을 위해 일합니다 :
- 속성
- 인덱서
- 행동 양식
- 연산자
C # 7.0 에서 추가됨
그러나 다음 멤버에서는 작동하지 않습니다.
- 중첩 유형
- 행사
- 필드
답변
좋아 … 나는 그들이 다르다는 의견을 냈지만 정확히 어떻게 알 수는 없지만 지금은 알고 있습니다.
String Property { get; } = "value";
와 같지 않다
String Property => "value";
차이점은 다음과 같습니다.
자동 초기화 프로그램을 사용하면 속성이 값의 인스턴스를 생성하고 해당 값을 지속적으로 사용합니다. 위의 게시물에는 Bill Wagner에 대한 깨진 링크가 있습니다. 이는 잘 설명하고 있으며, 본인이 이해하기 위해 올바른 링크를 검색했습니다.
내 상황에서는 ViewModel에서 View에 대한 명령을 자동으로 초기화하는 속성이 있습니다. 표현식 본문 이니셜 라이저를 사용하도록 속성을 변경하고 CanExecute 명령이 작동을 멈췄습니다.
여기에 모습이 있고 여기에 무슨 일이 있었는지입니다.
Command MyCommand { get; } = new Command(); //works
여기 내가 바꿨 던 것이 있습니다.
Command MyCommand => new Command(); //doesn't work properly
차이점은 내가 사용할 때입니다. { get; } =
은 해당 속성에서 SAME 명령을 만들고 참조 입니다. 내가 사용할 때 =>
실제로 새 명령을 만들고 속성이 호출 될 때마다 반환합니다. 따라서 CanExecute
항상 해당 명령의 새 참조를 업데이트하도록 지시했기 때문에 명령을 on으로 업데이트 할 수 없었 습니다.
{ get; } = // same reference
=> // new reference
모든 말은, 당신이 단지 백업 필드를 가리키고 있다면 잘 작동합니다. 이것은 자동 또는 표현식 본문이 반환 값을 생성 할 때만 발생합니다.
답변
이것은 람다와 같은 함수를 사용하여 getter 전용 속성을 정의 할 수있는 표현식 본문 멤버라고하는 C # 6의 새로운 기능입니다.
다음과 같은 경우 구문 설탕 으로 간주되지만 동일한 IL을 생성 하지 못할 수 있습니다 .
public int MaxHealth
{
get
{
return Memory[Address].IsValid
? Memory[Address].Read<int>(Offs.Life.MaxHp)
: 0;
}
}
위의 두 버전을 모두 컴파일하고 각각에 대해 생성 된 IL을 비교하면 거의 동일 .
다음은 이름이 지정된 클래스에 정의 된 경우이 답변의 클래식 버전에 대한 IL입니다 TestClass
.
.property instance int32 MaxHealth()
{
.get instance int32 TestClass::get_MaxHealth()
}
.method public hidebysig specialname
instance int32 get_MaxHealth () cil managed
{
// Method begins at RVA 0x2458
// Code size 71 (0x47)
.maxstack 2
.locals init (
[0] int32
)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldfld class [mscorlib]System.Collections.Generic.Dictionary`2<int64, class MemoryAddress> TestClass::Memory
IL_0007: ldarg.0
IL_0008: ldfld int64 TestClass::Address
IL_000d: callvirt instance !1 class [mscorlib]System.Collections.Generic.Dictionary`2<int64, class MemoryAddress>::get_Item(!0)
IL_0012: ldfld bool MemoryAddress::IsValid
IL_0017: brtrue.s IL_001c
IL_0019: ldc.i4.0
IL_001a: br.s IL_0042
IL_001c: ldarg.0
IL_001d: ldfld class [mscorlib]System.Collections.Generic.Dictionary`2<int64, class MemoryAddress> TestClass::Memory
IL_0022: ldarg.0
IL_0023: ldfld int64 TestClass::Address
IL_0028: callvirt instance !1 class [mscorlib]System.Collections.Generic.Dictionary`2<int64, class MemoryAddress>::get_Item(!0)
IL_002d: ldarg.0
IL_002e: ldfld class Offs TestClass::Offs
IL_0033: ldfld class Life Offs::Life
IL_0038: ldfld int64 Life::MaxHp
IL_003d: callvirt instance !!0 MemoryAddress::Read<int32>(int64)
IL_0042: stloc.0
IL_0043: br.s IL_0045
IL_0045: ldloc.0
IL_0046: ret
} // end of method TestClass::get_MaxHealth
다음은 이름이 지정된 클래스에 정의 된 표현식 본문 멤버 버전의 IL입니다 TestClass
.
.property instance int32 MaxHealth()
{
.get instance int32 TestClass::get_MaxHealth()
}
.method public hidebysig specialname
instance int32 get_MaxHealth () cil managed
{
// Method begins at RVA 0x2458
// Code size 66 (0x42)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldfld class [mscorlib]System.Collections.Generic.Dictionary`2<int64, class MemoryAddress> TestClass::Memory
IL_0006: ldarg.0
IL_0007: ldfld int64 TestClass::Address
IL_000c: callvirt instance !1 class [mscorlib]System.Collections.Generic.Dictionary`2<int64, class MemoryAddress>::get_Item(!0)
IL_0011: ldfld bool MemoryAddress::IsValid
IL_0016: brtrue.s IL_001b
IL_0018: ldc.i4.0
IL_0019: br.s IL_0041
IL_001b: ldarg.0
IL_001c: ldfld class [mscorlib]System.Collections.Generic.Dictionary`2<int64, class MemoryAddress> TestClass::Memory
IL_0021: ldarg.0
IL_0022: ldfld int64 TestClass::Address
IL_0027: callvirt instance !1 class [mscorlib]System.Collections.Generic.Dictionary`2<int64, class MemoryAddress>::get_Item(!0)
IL_002c: ldarg.0
IL_002d: ldfld class Offs TestClass::Offs
IL_0032: ldfld class Life Offs::Life
IL_0037: ldfld int64 Life::MaxHp
IL_003c: callvirt instance !!0 MemoryAddress::Read<int32>(int64)
IL_0041: ret
} // end of method TestClass::get_MaxHealth
참조 https://msdn.microsoft.com/en-us/magazine/dn802602.aspx를C # 6의이 기능 및 기타 새로운 기능에 대한 자세한 내용 를 .
이 게시물 C # 3.0+의 속성과 필드의 차이점을 참조하십시오. 에서 필드와 속성 게터의 .
최신 정보:
C # 7.0에는 식 본문 멤버가 속성, 생성자, 종료 자 및 인덱서를 포함하도록 확장되었습니다.
답변
Expression Bodied Member 라고 하며 C # 6에 도입되었습니다 get
. 유일한 속성 에 대한 구문 설탕 일뿐 입니다.
다음과 같습니다.
public int MaxHealth { get { return Memory[Address].IsValid ?
Memory[Address].Read<int>(Offs.Life.MaxHp) : 0; }
메소드 선언과 동등한 것은 사용 가능합니다.
public string HelloWorld() => "Hello World";
주로 상용구를 단축 할 수 있습니다.
답변
C # 6을 사용하는 경우 다른 중요한 점이 있습니다.
‘=>’대신 ‘수’사용할 수 있습니다 및입니다 만 ‘에서만 얻을’메소드 – 그것은 ‘세트’와 함께 사용할 수 없습니다.
C # 7의 경우 아래 @avenmore의 주석을 참조하십시오. 이제 더 많은 곳에서 사용할 수 있습니다. 여기 좋은 참조가 있습니다-https: //csharp.christiannagel.com/2017/01/25/expressionbodiedmembers/
답변
컴파일러가 식 본문 속성 멤버를 만나면 본질적으로 다음과 같이 getter로 변환합니다.
다음 스크린 샷을 참조하십시오 ( SharpLab 링크 사용 ).
public string APIBasePath => Configuration.ToolsAPIBasePath;
로 변환하다
public string APIBasePath
{
get
{
return Configuration.ToolsAPIBasePath;
}
}