Chiamando Push()
e Pop()
un'istanza di Stack<T>
in una singola riga ottengo un comportamento diverso rispetto all'esecuzione dello stesso codice imho in due righe.Ordine di operazione imprevisto nello stackrelativo a un rivestimento
Il seguente frammento di codice riproduce il comportamento:
static void Main(string[] args)
{
Stack<Element> stack = new Stack<Element>();
Element e1 = new Element { Value = "one" };
Element e2 = new Element { Value = "two" };
stack.Push(e1);
stack.Push(e2);
Expected(stack); // element on satck has value "two"
//Unexpected(stack); // element on stack has value "one"
Console.WriteLine(stack.Peek().Value);
Console.ReadLine();
}
public static void Unexpected(Stack<Element> stack)
{
stack.Peek().Value = stack.Pop().Value;
}
public static void Expected(Stack<Element> stack)
{
Element e = stack.Pop();
stack.Peek().Value = e.Value;
}
La classe Element è davvero fondamentale:
public class Element
{
public string Value
{
get;
set;
}
}
Con questo codice ottengo il seguente risultato (.NET 3.5, Win 7, completamente patchato):
- Calling
Expected()
(versione con due linee) lea ves un elemento nello stack conValue
impostato su"two"
. - Quando si chiama
Unexpected()
(Versione con una linea) ottengo un elemento sul risma alValue
insieme a"one"
.
L'unica ragione della differenza che potevo immaginare era la precedenza dell'operatore. Poiché l'operatore di assegnazione (=
) ha il lowest precedence, non vedo alcun motivo per cui i due metodi dovrebbero comportarsi in modo diverso.
Ho anche avuto uno sguardo alla IL generato:
.method public hidebysig static void Unexpected(class [System]System.Collections.Generic.Stack`1<class OperationOrder.Element> stack) cil managed
{
.maxstack 8
L_0000: ldarg.0
L_0001: callvirt instance !0 [System]System.Collections.Generic.Stack`1<class OperationOrder.Element>::Peek()
L_0006: ldarg.0
L_0007: callvirt instance !0 [System]System.Collections.Generic.Stack`1<class OperationOrder.Element>::Pop()
L_000c: callvirt instance string OperationOrder.Element::get_Value()
L_0011: callvirt instance void OperationOrder.Element::set_Value(string)
L_0016: ret
}
Io non sono un crepa IL, ma per me questo codice sembra ancora buono ans dovrebbero lasciare un elemento sullo stack con valore impostato su " Due".
Qualcuno mi può spiegare il motivo per cui il metodo Unexpected()
fa qualcosa di diverso rispetto Expected()
?
Grazie mille!
Lukas
Hai ragione. Avrei dovuto pensarci. Grazie mille! –