我看过他们在无数块的C#代码都被使用了,我想知道何时使用i++或++i(i为某数量的变量一样int,float,double,等).谁知道这个?
Eri*_*ert 417
不幸的是,这个问题的典型答案是,一个人在"剩余的操作之前"进行增量,另一个人在"剩余操作之后"进行增量.虽然这直觉上得到了这个想法,但这种说法完全错了.该时间事件的顺序是在C#中非常明确的,这是强调不认为++的前缀和后缀的版本都可以以不同的顺序的东西相对于其他操作的情况.
毫不奇怪,你会看到这个问题有很多错误的答案.很多"自学C#"的书也错了.此外,C#的方式与C的方式不同.许多人认为C#和C是同一种语言; 他们不是.在我看来,C#中增量和减量运算符的设计避免了C语言中这些运算符的设计缺陷.
必须回答两个问题才能确定前缀和后缀++在C#中的确切操作.第一个问题是结果是什么?第二个问题是增量的副作用何时发生?
这两个问题的答案都不明显,但一旦你看到它,它实际上很简单.让我准确地为您拼出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);
}
}
Run Code Online (Sandbox Code Playgroud)
结果如下......
Test 1: ++x
Current:1 Passed-in:1
Test 2: x++
Current:2 Passed-in:1
Test 3: ++x
Current:3 Passed-in:3
Run Code Online (Sandbox Code Playgroud)
在第一个测试中,您可以看到currentValue传递给TestMethod()扩展的两者和内容都显示了与预期相同的值.
但是,在第二种情况下,人们会试着告诉你在调用之后currentValue发生的增量,但正如你从结果中看到的那样,它发生在调用之前,如'Current:2'结果所示.TestMethod()
在这种情况下,首先将值currentValue存储在临时值中.接下来,将该值的递增版本存储回currentValue但不接触仍存储原始值的临时值.最后,临时传递给TestMethod().如果增量发生后调用TestMethod()那就写出来的一样,非递增值的两倍,但事实并非如此.
重要的是要注意,两个
currentValue++和++currentValue操作返回的值都是基于临时而不是操作退出时存储在变量中的实际值.回想一下上面的操作顺序,前两个步骤将变量的当前值复制到临时值中.那就是用来计算回报价值的东西; 在前缀版本的情况下,临时值增加,而在后缀版本的情况下,它是直接/非增量的值.初始存储到临时变量后,变量本身不会再次读取.
更简单地说,后缀版本返回从变量读取的值(即临时值),而前缀版本返回写回变量的值(即临时值的递增值).既不返回变量的值.
这一点很重要,因为变量本身可能是易失性的,并且在另一个线程上发生了变化,这意味着这些操作的返回值可能与存储在变量中的当前值不同.
令人惊讶的是,人们对优先级,关联性以及执行副作用的顺序非常困惑,我怀疑主要是因为它在C语言中如此令人困惑.C#经过精心设计,在所有这些方面都不那么混乱.对于这些问题的一些额外分析,包括我进一步证明前缀和后缀操作"及时移动东西"的想法的虚假性,请参阅:
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
此外,在考虑其他具有副作用的操作时,我们会遇到类似的微妙问题,例如链式简单赋值:
这里有一篇有趣的帖子,说明为什么增量运算符会导致C#中的值而不是变量中的值:
Kie*_*one 185
奇怪的是,看起来其他两个答案并没有拼出来,这绝对值得说:
i++意思是'告诉我价值i,然后增加'
++i意思是"递增i,然后告诉我价值"
它们是预增量,后增量运算符. 在这两种情况下,变量都会递增,但如果要在完全相同的情况下获取两个表达式的值,则结果会有所不同.
dcp*_*dcp 23
如果你有:
int i = 10;
int x = ++i;
Run Code Online (Sandbox Code Playgroud)
然后x会11.
但如果你有:
int i = 10;
int x = i++;
Run Code Online (Sandbox Code Playgroud)
然后x会10.
请注意,Eric指出,在两种情况下,增量同时发生,但它是不同的结果给出的值(感谢Eric!).
一般来说,我喜欢使用,++i除非有充分的理由不这样做.例如,在编写循环时,我喜欢使用:
for (int i = 0; i < 10; ++i) {
}
Run Code Online (Sandbox Code Playgroud)
或者,如果我只需要增加一个变量,我喜欢使用:
++x;
Run Code Online (Sandbox Code Playgroud)
通常情况下,这种方式或其他方式没有多大意义并且归结为编码风格,但如果您在其他任务中使用运算符(例如在我的原始示例中),那么了解潜在的副作用很重要.
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.
Run Code Online (Sandbox Code Playgroud)
这回答了你的问题了吗 ?
运算符的工作方式是它同时递增,但如果它在变量之前,则表达式将使用递增/递减的变量进行求值:
int x = 0; //x is 0
int y = ++x; //x is 1 and y is 1
Run Code Online (Sandbox Code Playgroud)
如果它在变量之后,当前语句将使用原始变量执行,就好像它还没有递增/递减一样:
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
Run Code Online (Sandbox Code Playgroud)
除非必要,否则我同意dcp使用预增量/减量(++ x).真的是我使用后递增/递减的唯一时间是while循环或那种循环.这些循环是相同的:
while (x < 5) //evaluates conditional statement
{
//some code
++x; //increments x
}
Run Code Online (Sandbox Code Playgroud)
要么
while (x++ < 5) //evaluates conditional statement with x value before increment, and x is incremented
{
//some code
}
Run Code Online (Sandbox Code Playgroud)
你也可以在索引数组时这样做:
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);
Run Code Online (Sandbox Code Playgroud)
等等......
小智 5
只是为了记录,在 C++ 中,如果您可以使用(即)您不关心操作的顺序(您只想递增或递减并稍后使用它),前缀运算符更有效,因为它没有必须创建对象的临时副本。不幸的是,大多数人使用 posfix (var++) 而不是 prefix (++var),因为这是我们最初学到的。(我在一次采访中被问到这个问题)。不确定这在 C# 中是否正确,但我认为是这样。
| 归档时间: |
|
| 查看次数: |
90736 次 |
| 最近记录: |