我看过他们在无数块的C#代码都被使用了,我想知道何时使用i++
或++i
(i
是像许多变量int
,float
,double
,等)。有人知道吗?
我看过他们在无数块的C#代码都被使用了,我想知道何时使用i++
或++i
(i
是像许多变量int
,float
,double
,等)。有人知道吗?
Answers:
奇怪的是,其他两个答案似乎并没有清楚说明,这绝对是值得一说的:
i++
表示“告诉我的值i
,然后递增”
++i
意思是“递增i
,然后告诉我价值”
它们是预增,后增运算符。 在这两种情况下,变量都是递增的,但是如果在完全相同的情况下采用两个表达式的值,结果将有所不同。
不幸的是,此问题的典型答案是已经在此处发布,一个答案是在剩余操作之前“递增”,而另一个则在“剩余”操作之后递增。尽管从直觉上可以理解这个想法,但是从表面上看,这种说法是完全错误的。该时间事件的顺序是在C#中非常明确的,这是强调不认为++的前缀(++ VAR)和后缀(VAR ++)版本都以不同的顺序的东西相对于其他操作的情况。
毫不奇怪,您会看到很多关于该问题的错误答案。许多“自学C#”书籍也弄错了。同样,C#的执行方式与C的执行方式不同。很多人认为C#和C是同一语言。他们不是。在我看来,C#中的递增和递减运算符的设计避免了C中这些运算符的设计缺陷。
要确定C#中前缀和后缀++的确切操作,必须回答两个问题。第一个问题是结果是什么?第二个问题是增量的副作用何时发生?
这两个问题的答案并不明显,但是一旦您看到它,实际上就很简单了。让我为您详细说明x ++和++ x对变量x的作用。
对于前缀形式(++ x):
对于后缀形式(x ++):
注意事项:
首先,两种情况下事件的时间顺序完全相同。同样,事件的时间顺序在前缀和后缀之间变化绝对不是绝对的情况。说评估在其他评估之前或之后进行是完全错误的。在两种情况下,评估都以完全相同的顺序进行,步骤1到步骤4完全相同。的唯一区别就是最后一步 -结果是否是临时或新的,增加值的价值。
您可以使用简单的C#控制台应用程序轻松演示这一点:
public class Application
{
public static int currentValue = 0;
public static void Main()
{
Console.WriteLine("Test 1: ++x");
(++currentValue).TestMethod();
Console.WriteLine("\nTest 2: x++");
(currentValue++).TestMethod();
Console.WriteLine("\nTest 3: ++x");
(++currentValue).TestMethod();
Console.ReadKey();
}
}
public static class ExtensionMethods
{
public static void TestMethod(this int passedInValue)
{
Console.WriteLine("Current:{0} Passed-in:{1}",
Application.currentValue,
passedInValue);
}
}
结果如下...
Test 1: ++x
Current:1 Passed-in:1
Test 2: x++
Current:2 Passed-in:1
Test 3: ++x
Current:3 Passed-in:3
在第一个测试中,您可以看到currentValue
与TestMethod()
扩展中传递的内容和预期值都显示相同的值。
但是,在第二种情况下,人们会尝试告诉您,对的调用之后currentValue
发生的增量是增加的,但是正如您从结果中看到的那样,它发生在调用之前,如'Current:2'结果所示。TestMethod()
在这种情况下,首先将的值currentValue
存储在一个临时文件中。接下来,该值的递增版本将被存储回去,currentValue
但不触摸仍存储原始值的临时项。最后,该临时变量传递给TestMethod()
。如果增量是在调用TestMethod()
之后发生的,则它将写出相同的非增量值两次,但不会。
请务必注意,从
currentValue++
和++currentValue
操作返回的值都是基于临时值,而不是基于任一操作退出时存储在变量中的实际值。回想一下上面操作的顺序,前两个步骤将变量的当前值复制到临时变量中。那就是用来计算返回值的东西。在前缀版本的情况下,临时值是递增的,而在后缀版本的情况下,临时值是直接/非递增。初始存储到临时变量后,不会再次读取变量本身。
简而言之,后缀版本返回从变量读取的值(即临时值),而前缀版本返回写回变量的值(即临时值递增)。都不返回变量的值。
了解这一点很重要,因为变量本身可能是易失性的,并且已在另一个线程上更改,这意味着这些操作的返回值可能与存储在变量中的当前值不同。
人们总是对优先级,关联性和执行副作用的顺序感到困惑,这是令人惊讶的普遍现象,我怀疑这主要是因为它在C中是如此令人困惑。C#经过精心设计,在所有这些方面都不会造成混乱。有关这些问题的其他分析,包括我进一步说明了前缀和后缀操作“及时移动”的想法是虚假的,请参阅:
https://ericlippert.com/2009/08/10/precedence-vs-order-redux/
这导致了这样的问题:
int [] arr = {0}; int值= arr [arr [0] ++]; 值= 1?
您可能还对我以前关于该主题的文章感兴趣:
https://ericlippert.com/2008/05/23/precedence-vs-associativity-vs-order/
和
https://ericlippert.com/2007/08/14/c-and-the-pit-of-despair/
还有一个有趣的情况,其中C使得很难推理正确性:
https://docs.microsoft.com/archive/blogs/ericlippert/bad-recursion-revisited
此外,在考虑其他具有副作用的操作(例如链接的简单分配)时,我们也会遇到类似的细微问题:
https://docs.microsoft.com/archive/blogs/ericlippert/chaining-simple-assignments-is-not-so-simple
而这里就是为什么增量运营商造成了一个有趣的岗位值在C#中,而不是在变量:
i++
或++i
用于代码中,C#只是在后台运行;在后台。我编写C#时要升到高于该级别的抽象水平,因此,如果这对于您的C#代码确实很重要,则您可能已经使用了错误的语言。
i++;
),for (int i = 0; i < x; i++)
而且……我非常非常很高兴!(而且我从未使用过前缀运算符)。如果我必须写一些需要高级程序员2分钟才能解密的内容,那么……最好再写一行代码或引入一个临时变量:-)我认为您的“文章”(我赢了“不称其为”答案”)证明了我的选择:-)
如果你有:
int i = 10;
int x = ++i;
然后x
将11
。
但是,如果您有:
int i = 10;
int x = i++;
然后x
将10
。
请注意,正如Eric所指出的,在两种情况下,增量都是同时发生的,但是结果是给出的值是不同的(感谢Eric!)。
通常,++i
除非有充分的理由,否则我会喜欢使用。例如,在编写循环时,我喜欢使用:
for (int i = 0; i < 10; ++i) {
}
或者,如果我只需要增加一个变量,我喜欢使用:
++x;
通常,一种或另一种方法没有多大意义,只能归结为编码风格,但是,如果您在其他分配中使用运算符(例如在我的原始示例中),请务必注意潜在的副作用。
i
用于变量名,而不是var
因为它是C#关键字。
int i = 0;
Console.WriteLine(i++); // Prints 0. Then value of "i" becomes 1.
Console.WriteLine(--i); // Value of "i" becomes 0. Then prints 0.
这回答了你的问题了吗 ?
运算符的工作方式是在同一时间递增,但是如果在变量之前,则表达式将使用递增/递减的变量求值:
int x = 0; //x is 0
int y = ++x; //x is 1 and y is 1
如果在变量之后,则当前语句将使用原始变量执行,就好像尚未递增/递减一样:
int x = 0; //x is 0
int y = x++; //'y = x' is evaluated with x=0, but x is still incremented. So, x is 1, but y is 0
我同意dcp除非需要使用预增减(++ x)。实际上,我唯一使用后递增/后递减的时间是在while循环或此类循环中。这些循环是相同的:
while (x < 5) //evaluates conditional statement
{
//some code
++x; //increments x
}
要么
while (x++ < 5) //evaluates conditional statement with x value before increment, and x is incremented
{
//some code
}
您还可以在索引数组等时执行此操作:
int i = 0;
int[] MyArray = new int[2];
MyArray[i++] = 1234; //sets array at index 0 to '1234' and i is incremented
MyArray[i] = 5678; //sets array at index 1 to '5678'
int temp = MyArray[--i]; //temp is 1234 (becasue of pre-decrement);
等等...
仅出于记录目的,在C ++中,如果可以使用(即)您不关心操作的顺序(您只想递增或递减并在以后使用它),则前缀运算符会更有效,因为它不会必须创建对象的临时副本。不幸的是,大多数人使用posfix(var ++)而不是前缀(++ var),只是因为这是我们最初学到的。(在一次采访中有人问我)。不知道在C#中是否正确,但我认为应该是这样。