Я столкнулся с ошибкой в коде, который только воспроизводится, когда код создается с включенной оптимизацией. Я сделал консольное приложение, которое копирует логику для тестирования (код ниже). Вы будете видеть, что, когда оптимизации включают, 'значение' становится пустым после выполнения этой недопустимой логики:
if ((value == null || value == new string[0]) == false)
Фиксация является прямой и комментируется ниже незаконного кода. Но... Я более обеспокоен, что, возможно, столкнулся с ошибкой в ассемблере, или возможно у кого-то еще есть объяснение того, почему значение устанавливается в NULL.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace memory_testing
{
class Program
{
sta tic void Main(string[] args)
{
while(true)
{
Console.Write("Press any key to start...");
Console.ReadKey();
Console.WriteLine();
PrintManagerUser c = new PrintManagerUser();
c.MyProperty = new string[1];
}
}
}
public class PrintManager
{
public void Print(string key, object value)
{
Console.WriteLine("Key is: " + key);
Console.WriteLine("Value is: " + value);
}
}
public class PrintManagerUser
{
public string[] MyProperty
{
get { return new string[100]; }
set
{
Console.WriteLine("Pre-check Value is: " + value);
if ((value == null || value == new string[0]) == false)
{
Console.WriteLine("Post-check Value is: " + value);
new PrintManager().Print("blah", value);
}
//if (value != null && value.Length > 0)
//{
// new PrintManager().Print("blah", value);
//}
}
}
}
}
Нормальный вывод должен быть:
Pre-check Value is: System.String[]
Post-check Value is: System.String[]
Key is: blah
Value is: System.String[]
Ошибочный вывод:
Pre-check Value is: System.String[]
Post-check Value is:
Key is: blah
Value is:
Мой ENV является VM рабочий Windows Server 2003 R2 с.NET 3,5 SP1. Использование Системы Команды VS2008.
Спасибо,
Brian
Да, ваше выражение смертельно пушает оптимизатора JIT. Сгенерированный машинный код выглядит следующим образом:
if ((value == null || value == new string[0]) == false)
00000027 test esi,esi ; value == null?
00000029 je 00000075
0000002b xor edx,edx ; new string[0]
0000002d mov ecx,6D913BD2h
00000032 call FFD20BC8
00000037 cmp eax,esi ; (value == new string[0]) == false?
00000039 je 00000075
{
Console.WriteLine("Post-check Value is: " + value);
0000003b mov ecx,dword ptr ds:[03532090h] ; "Post-check value is: "
00000041 xor edx,edx ; BUGBUG not null!
00000043 call 6D70B7E8 ; String.Concat()
00000048 mov esi,eax ;
0000004a call 6D72BE08 ; get Console.Out
0000004f mov ecx,eax
00000051 mov edx,esi
00000053 mov eax,dword ptr [ecx]
00000055 call dword ptr [eax+000000D8h] ; Console.WriteLine()
Оптасрение происходит по адресу 41, оптимизатор пришел к выводу, что значение всегда будет нулевым, поэтому он напрямую передает NULL для String.concat ().
Для сравнения, это код, который генерируется, когда jit Optimization отключается:
Console.WriteLine("Post-check Value is: " + value);
00000056 mov ecx,dword ptr ds:[03342090h]
0000005c mov edx,dword ptr [ebp-8]
0000005f call 6D77B790
Код был перемещен, но отметить, что в адресе 5C он теперь использует локальную переменную (значение) вместо NULL.
Вы можете сообщить об этой ошибке в Connect.microsoft.com. Обходной путь прост:
if (value != null)
{
Console.WriteLine("Post-check Value is: " + value);
new PrintManager().Print("blah", value);
}
Я нахожусь на X64, и сначала не мог воспроизвести проблему. Затем я указал цель как x86, и это случилось со мной. Вернуться к X64, и ушло. Не уверен, что именно это значит, но теперь я вернулся взад и вперед несколько раз.
value == new string[0]
Для меня это выглядит как странное заявление. Вы сравниваете два массива строк с утверждением равным. Это приведет к истине только в том случае, если они оба будут указывать на один и тот же массив, что маловероятно. Пока это не объясняет, почему в оптимизированном варианте код ведет себя по-другому.
Конечно, похоже на ошибку, она воспроизводится, когда вы меняете операторы, как этот?
if (false == (null == value || new string[0] == value))
Эта ошибка, похоже, была исправлена в .NET 4 ( бета 2). Вот оптимизированная разборка x86 для выделенного бита nobugz выше:
Console.WriteLine("Post-check Value is: " + value);
00000056 mov ecx,dword ptr ds:[033C2090h]
0000005c mov edx,dword ptr [ebp-8]
0000005f call 65D8FE10
Программа также отображает ожидаемый результат как в оптимизированном, так и в неоптимизированном режимах.