대 입문이 왜 값을 반환합니까?
이것은 허용됩니다 :
int a, b, c;
a = b = c = 16;
string s = null;
while ((s = "Hello") != null) ;
나의 이해에, 할당 s = ”Hello”;
만의 원인이해야 “Hello”
할당 할 수 s
있지만, 작업이 어떤 값을 반환하지 않아야합니다. 그것이 사실이라면, 아무것도 비교되지 ((s = "Hello") != null)
않기 때문에 오류가 발생합니다 null
.
대 입문이 값을 반환하도록 허용하는 이유는 무엇입니까?
내 이해에 따르면 과제 s = "Hello"; "Hello"만 s에 지정해야하지만 작업이 값을 반환하지 않아야합니다.
이해가 100 % 잘못되었습니다. 왜이 거짓을 믿는지 설명 할 수 있습니까?
대 입문이 값을 반환하도록 허용하는 이유는 무엇입니까?
우선, 할당 문 은 값을 생성하지 않습니다. 대입 식은 값을 생성합니다. 할당 표현은 법적 진술입니다. C #에는 합법적 인 표현 중 소수만 있습니다. 표현을 기다리고 있습니다. 인스턴스 생성, 증분, 감소, 호출 및 할당 표현식은 명령문이 필요한 곳에서 사용될 수 있습니다.
C #에는 일종의 값을 생성하지 않는 표현식, 즉 void를 반환하는 유형의 무언가 호출이 있습니다. 또는 결과 값이없는 작업을 대기하는 등의 다른 모든 유형의 표현식은 값 또는 변수 또는 참조 또는 속성 액세스 또는 이벤트 액세스 등을 생성합니다.
진술로 합법적 인 모든 표현은 부작용에 유용합니다 . 이것이 핵심 통찰력이며, 아마도 과제가 표현이 아니라 진술이어야한다는 직감의 원인이라고 생각합니다. 이상적으로는 명령문마다 정확히 하나의 부작용이 있고 표현식에는 부작용이 없습니다. 인 사이드 행하는 코드가 전혀 발현 맥락에서 사용될 수있는 비트 홀수.
이 기능을 허용하는 이유는 (1) 자주 사용하고 (2) C와 같은 언어에서는 관용적이기 때문입니다.
이 질문이 왜 C와 같은 언어로 관용적입니까?
불행히도 Dennis Ritchie는 더 이상 요청할 수 없지만 할당은 거의 항상 레지스터에 할당 된 값 보다 거의 남습니다 . C는 매우 "기계에 가까운"종류의 언어입니다. C의 디자인에 따라 기본적으로 "방금 할당 한 값을 계속 사용합니다"라는 언어 기능이 있다는 것이 그럴듯 해 보입니다. 이 기능을위한 코드 생성기를 작성하는 것은 매우 쉽습니다. 할당 된 값을 저장 한 레지스터를 계속 사용하면됩니다.
답변을 제공하지 않았습니까? 그것은 당신이 언급 한 종류의 구성을 정확하게 가능하게하는 것입니다.
대입 연산자의이 속성이 사용되는 일반적인 경우는 파일에서 행을 읽는 것입니다.
string line;
while ((line = streamReader.ReadLine()) != null)
// ...
할당 표현식을 가장 좋아하는 방식은 느리게 초기화 된 속성입니다.
private string _name;
public string Name
{
get { return _name ?? (_name = ExpensiveNameGeneratorMethod()); }
}
예를 들어 다음과 같이 과제를 연결할 수 있습니다.
a = b = c = 16;
다른 경우에는 단일 표현식으로 결과를 지정하고 확인할 수 있습니다.
while ((s = foo.getSomeString()) != null) { /* ... */ }
둘 다 모호한 이유 일 수 있지만 이러한 구성을 좋아하는 사람들이 분명히 있습니다.
이미 언급 한 이유 (할당 루프 내에서 할당 체인 및 설정 및 테스트 등) 외에이 기능이 필요한 명령문 을 올바르게 사용하려면 using
다음을 수행하십시오.
using (Font font3 = new Font("Arial", 10.0f))
{
// Use font3.
}
MSDN은 일회용 개체를 using 문 외부에 선언하지 않는 것이 좋습니다. 폐기 된 후에도 범위 내에 남아 있기 때문입니다 (MSDN 기사 링크 참조).
Eric Lippert가 자신의 답변에서 한 특정 요점에 대해 자세히 설명하고 다른 사람이 전혀 다루지 않은 특정 상황에 주목을하고 싶습니다. 에릭은 말했다 :
[...] 할당은 거의 항상 레지스터에 할당 된 값 뒤에 남습니다.
할당이 항상 왼쪽 피연산자에 할당하려고 시도한 값보다 뒤에 있다고 말하고 싶습니다. "거의 항상"만이 아닙니다. 그러나이 문제를 문서에서 언급하지 않았기 때문에 모르겠습니다. 이론적으로 "뒤로"두고 왼쪽 피연산자를 다시 평가하지 않는 매우 효과적인 구현 절차 일 수 있지만 효율적입니까?
이 스레드의 답변으로 지금까지 구성된 모든 예제에 대해 '효율적'입니다. 그러나 get 및 set 접근자를 사용하는 속성 및 인덱서의 경우 효율적입니까? 전혀. 이 코드를 고려하십시오.
class Test
{
public bool MyProperty { get { return true; } set { ; } }
}
Here we have a property, which isn't even a wrapper for a private variable. Whenever called upon he shall return true, whenever one tries to set his value he shall do nothing. Thus whenever this property is evaluated, he shall be truthy. Let's see what happens:
Test test = new Test();
if ((test.MyProperty = false) == true)
Console.WriteLine("Please print this text.");
else
Console.WriteLine("Unexpected!!");
Guess what it prints? It prints Unexpected!!
. As it turns out, the set accessor is indeed called, which does nothing. But thereafter, the get accessor is never called at all. The assignment simply leaves behind the false
value we tried to assign to our property. And this false
value is what the if statement evaluates.
I'll finish off with a real world example that got me researching this issue. I made an indexer which was a convenient wrapper for a collection (List<string>
) that a class of mine had as a private variable.
The parameter sent to the indexer was a string, which was to be treated as a value in my collection. The get accessor would simply return true or false if that value existed in the list or not. Thus the get accessor was another way to use the List<T>.Contains
method.
If the indexer's set accessor was called with a string as an argument and the right operand was a bool true
, he would add that parameter to the list. But if the same parameter was sent to the accessor and the right operand was a bool false
, he would instead delete the element from the list. Thus the set accessor was used as a convenient alternative to both List<T>.Add
and List<T>.Remove
.
I thought I had a neat and compact "API" wrapping the list with my own logic implemented as a gateway. With the help of an indexer alone I could do many things with a few set of keystrokes. For instance, how can I try to add a value to my list and verify that it's in there? I thought this was the only line of code necessary:
if (myObject["stringValue"] = true)
; // Set operation succeeded..!
But as my earlier example showed, the get accessor which is supposed to see if the value really is in the list wasn't even called. The true
value was always left behind effectively destroying whatever logic I had implemented in my get accessor.
If assignment didn't return a value, the line a = b = c = 16
wouldn't work either.
Also being able to write things like while ((s = readLine()) != null)
can be useful sometimes.
So the reason behind letting assignment return the assigned value, is to let you do those things.
I think you're misunderstanding how the parser is going to interpret that syntax. The assignment will be evaluated first, and the result will then be compared to NULL, i.e. the statement is equivalent to:
s = "Hello"; //s now contains the value "Hello"
(s != null) //returns true.
As others have pointed out, the result of an assignment is the assigned value. I find it hard to imagine the advantage to having
((s = "Hello") != null)
and
s = "Hello";
s != null;
not be equivalent...
I think the main reason is the (intentional) similarity with C++ and C. Making the assigment operator (and a lot of other language constructs) behave like their C++ counterparts just follows the principle of least surprise, and any programmer coming from another curly-bracket language can use them without spending much thought. Being easy to pick up for C++ programmers was one of the main design goals for C#.
For the two reasons you include in your post
1) so you can do a = b = c = 16
2) so you can test if an assignment succeeded if ((s = openSomeHandle()) != null)
The fact that 'a++' or 'printf("foo")' may be useful either as a self-contained statement or as a part of a larger expression means that C has to allow for the possibility that expression results may or may not be used. Given that, there's a general notion that expressions which might usefully 'return' a value may as well do so. Assignment chaining can be slightly "interesting" in C, and even more interesting in C++, if all the variables in question do not have precisely the same type. Such usages are probably best avoided.
Another great example use-case, I use this all the time:
var x = _myVariable ?? (_myVariable = GetVariable());
//for example: when used inside a loop, "GetVariable" will be called only once
An extra advantage I don't see given in the answers here, is that the syntax for assignment is based on arithmetic.
Now x = y = b = c = 2 + 3
means something different in arithmetic than a C-style language; in arithmetic its an assertion, we state that x is equal to y etc. and in a C-style language it's an instruction that makes x equal to y etc. after it is executed.
This said, there's still enough relation between the arithmetic and the code that it doesn't make sense to disallow what is natural in the arithmetic unless there's a good reason. (The other thing that C-style languages took from the use of the equals symbol is the use of == for equality comparison. Here though because the right-most == returns a value this sort of chaining would be impossible.)
참고URL : https://stackoverflow.com/questions/3807192/why-do-assignment-statements-return-a-value
'Programing' 카테고리의 다른 글
명령 프롬프트에서 .exe를 실행하기위한 Bat 파일 (0) | 2020.07.08 |
---|---|
확인 : 명령이 실패한 후 계속하는 방법? (0) | 2020.07.08 |
Vim 시작 시간 프로파일 링 (0) | 2020.07.08 |
Angular2에서 다른 구성 요소 함수를 호출하는 방법 (0) | 2020.07.08 |
인터페이스 빌더에서 자동 레이아웃 (제약) 제거 (0) | 2020.07.08 |