i ++和++ i有什么区别?
我已经看到他们都被用于无数的C#代码块,我想知道什么时候使用i++
或++i
( i
是一个数字variables,如int
, float
, double
等)。 任何人知道这一点?
奇怪的是,其他两个答案看起来不拼出来,这绝对值得说:
i++
意思是“告诉我我的价值,然后增加”
++i
意思是“增加i
,然后告诉我的价值”
他们是预增,后增加的运营商。 在这两种情况下,variables都是递增的 ,但是如果您要在完全相同的情况下使用两个expression式的值,结果将会不同。
这个问题的典型答案,不幸的是已经在这里发布了,其中一个是在剩余操作之前“增加”增量,另一个是在剩余操作之后“增加”增量。 虽然直观地把这个想法传达出来,但是这个陈述完全是错误的 。 在C#中, 时间事件的顺序是非常明确的,重点不在于++的前缀和后缀版本以不同于其他操作的顺序执行操作。
这个问题你会看到很多错误的答案也就不足为奇了。 很多人“教自己C#”的书也错了。 而且,C#的方式与C的方式不同。 许多人认为C#和C是相同的语言, 他们不是。 在我看来,C#中增量和减量运算符的devise避免了这些运算符在C中的devise缺陷。
有两个问题需要回答,以确定在C#中前缀和后缀++的操作是什么。 第一个问题是结果是什么? 第二个问题是什么时候增量的副作用发生?
这两个问题的答案都不是很明显,但是一旦你看到它,其实很简单。 让我为你准确地说明x ++和++ x为variablesx做些什么。
对于前缀forms:
- 评估x来产生variables
- variables的值被复制到一个临时位置
- 临时值会递增以产生一个新值(不会覆盖临时!)
- 新值存储在variables中
- 操作的结果是新的值 (即临时增加的值)
对于后缀forms:
- 评估x来产生variables
- variables的值被复制到一个临时位置
- 临时值会递增以产生一个新值(不会覆盖临时!)
- 新值存储在variables中
- 操作的结果是临时值
有些事情要注意:
首先, 两种情况下的事件顺序是完全一样的 。 同样,绝对不是 事件的时间顺序在前缀和后缀之间变化的情况。 说评价发生在其他评价之前或其他评价之后是完全错误的。 在这两种情况下,评估的执行顺序完全相同 ,步骤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
在第一个testing中,您可以看到currentValue
和传入到TestMethod()
扩展名的内容都显示了相同的值,如预期的那样。
然而,在第二种情况下,人们会试图告诉你,在调用TestMethod()
之后 , currentValue
的增量会发生,但是从结果中可以看出,它发生在调用之前 ,如“Current:2”结果。
在这种情况下,首先将currentValue
的值存储在临时表中。 接下来,将该值的递增版本存储在currentValue
但不触及仍然存储原始值的临时值。 最后,临时被传递给TestMethod()
。 如果增量在调用TestMethod()
之后发生,那么它将写出相同的非增量值两次,但不是。
请注意,
currentValue++
和++currentValue
操作返回的值基于操作退出时临时variables而非variables中存储的实际值。按照上面的操作顺序,前两个步骤将variables的当前值复制到临时值中。 这就是用来计算回报的价值; 在前缀版本的情况下,临时值递增,而在后缀版本的情况下,该值是直接/不递增的。 variables本身在初次存储到临时文件后不会被再次读取。
更简单地说,后缀版本返回从variables读取的值(即临时值),而前缀版本返回写回variables的值(即,临时值的递增值)。 既不返回variables的值。
这一点很重要,因为variables本身可能是易变的,并且在另一个线程上发生了变化,这意味着这些操作的返回值可能与variables中存储的当前值不同。
令人惊讶的是,人们对优先级,关联性和执行副作用的次序感到非常困惑,我怀疑主要是因为它在C中如此混乱.C#经过精心devise,在所有这些方面都不那么困惑。 对于这些问题的一些额外的分析,包括我进一步certificate了前缀和后缀操作“及时移动东西”的想法的错误:
http://blogs.msdn.com/b/ericlippert/archive/2009/08/10/precedence-vs-order-redux.aspx
这导致了这个问题:
int [] arr = {0}; int value = arr [arr [0] ++]; 值= 1?
您可能也对我之前关于这个主题的文章感兴趣:
http://blogs.msdn.com/b/ericlippert/archive/2008/05/23/precedence-vs-associativity-vs-order.aspx
和
http://blogs.msdn.com/b/ericlippert/archive/2007/08/14/c-and-the-pit-of-despair.aspx
还有一个有趣的例子,C让人很难理解正确性:
http://blogs.msdn.com/b/ericlippert/archive/2005/04/28/bad-recursion-revisited.aspx
另外,当考虑其他具有副作用的操作时,我们遇到类似的细微问题,例如链式简单分配:
这里有一个有趣的post,为什么增量运算符在C#中而不是在variables中产生值 :
为什么我不能用C语言来做++ i ++?
如果你有:
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) { }
或者,如果我只需要增加一个variables,我喜欢使用:
++x;
通常情况下,这种或那种方式没有多大意义,可以归结为编码风格,但是如果您在其他任务中使用运算符(例如在我的原始示例中),重要的是要注意潜在的副作用。
操作符的工作方式是同时递增,但如果它在variables之前,则expression式将使用递增/递减的variables进行计算:
int x = 0; //x is 0 int y = ++x; //x is 1 and y is 1
如果在variables之后,则当前语句将与原始variables一起被执行,就好像它还没有被递增/递减:
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
除非必要,我同意使用前增加/减量(++ x)的dcp。 真的是唯一一次我使用后递增/递减是在while循环或types的循环。 这些循环是相同的:
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);
等等等等
只是为了logging,在C ++中,如果你可以使用(即)你不关心操作的顺序(你只是想增加或减less,以后使用它),前缀运算符是更有效的,因为它不必须创build对象的临时副本。 不幸的是,大多数人使用posfix(var ++)而不是前缀(++ 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.
这回答了你的问题了吗 ?