Кажется, что я могу использовать DateTime для объекта, поэтому почему я не могу использовать массив DateTime [] для объекта []? Я знаю, что это имеет какое-то отношение к значениям/ссылочным типам, но разве бокс не позволяет мне это делать?
Почему я не могу использовать DateTime [] для объекта []?
Ответ 1
Ковариация массивов применяется только к массивам ссылочных типов. DateTime
- это тип значения, поэтому вы не можете назначить DateTime[]
переменной object[]
. Вам нужно будет явно создать массив объектов и скопировать значения. Другими словами, создайте новый экземпляр массива типа object[]
.
Есть много способов сделать это. Простое использование CopyTo()
должно быть достаточно.
DateTime[] x = new DateTime[] { ... };
object[] y = new object[x.Length];
x.CopyTo(y, 0);
Я провел несколько тестов. Вероятно, это не лучший способ сделать это, но он должен дать хорошее представление о том, что будет с правильным профилировщиком.
class Program
{
static void Main(string[] args)
{
var now = DateTime.Now;
var dates = new DateTime[5000000];
for (int i = 0; i < dates.Length; i++)
dates[i] = now.AddSeconds(i);
for (int i = 0; i < 5; i++)
{
Test("Test1", () =>
{
var result = new object[dates.LongLength];
for (long l = 0; l < result.LongLength; l++)
result[l] = dates[l];
return result;
});
Test("Test2", () =>
{
var result = new object[dates.LongLength];
dates.CopyTo(result, 0);
return result;
});
Test("Test3", () =>
{
var result = new object[dates.LongLength];
Array.Copy(dates, result, dates.LongLength);
return result;
});
Test("Test4", () =>
{
var result = Array.ConvertAll(dates, d => (object)d);
return result;
});
Test("Test5", () =>
{
var result = dates.Cast<object>().ToArray();
return result;
});
Test("Test6", () =>
{
var result = dates.Select(d => (object)d).ToArray();
return result;
});
Console.WriteLine();
}
}
static void Test<T>(string name, Func<T> fn)
{
var startMem = GC.GetTotalMemory(true);
var sw = Stopwatch.StartNew();
var result = fn();
sw.Stop();
var endMem = GC.GetTotalMemory(false);
var diff = endMem - startMem;
Console.WriteLine("{0}\tMem: {1,7}/{2,7} ({3,7})", name, startMem, endMem, diff);
Console.WriteLine("\tTime: {0,7} ({1,7})", sw.ElapsedMilliseconds, sw.ElapsedTicks);
}
}
Технические характеристики:
Win7Pro x64, Core2Quad [email protected], 4GiB DDR2 1066 (PC2-8500)
64-битная сборка (32-разрядная версия примерно одинаковая, всего меньше памяти)
Test1 Mem: 40086256/200087360 (160001104) Time: 444 (1230723) Test2 Mem: 40091352/200099272 (160007920) Time: 751 (2078001) Test3 Mem: 40091416/200099256 (160007840) Time: 800 (2213764) Test4 Mem: 40091480/200099256 (160007776) Time: 490 (1358326) Test5 Mem: 40091608/300762328 (260670720) Time: 1407 (3893922) Test6 Mem: 40091672/300762328 (260670656) Time: 756 (2092566) Test1 Mem: 40091736/200099184 (160007448) Time: 515 (1425098) Test2 Mem: 40091736/200099184 (160007448) Time: 868 (2404151) Test3 Mem: 40091736/200099160 (160007424) Time: 885 (2448850) Test4 Mem: 40091736/200099184 (160007448) Time: 540 (1494429) Test5 Mem: 40091736/300762240 (260670504) Time: 1479 (4093676) Test6 Mem: 40091736/300762216 (260670480) Time: 746 (2065095) Test1 Mem: 40091736/200099168 (160007432) Time: 500 (1383656) Test2 Mem: 40091736/200099160 (160007424) Time: 781 (2162711) Test3 Mem: 40091736/200099176 (160007440) Time: 793 (2194605) Test4 Mem: 40091736/200099184 (160007448) Time: 486 (1346549) Test5 Mem: 40091736/300762232 (260670496) Time: 1448 (4008145) Test6 Mem: 40091736/300762232 (260670496) Time: 749 (2075019) Test1 Mem: 40091736/200099184 (160007448) Time: 487 (1349320) Test2 Mem: 40091736/200099176 (160007440) Time: 781 (2162729) Test3 Mem: 40091736/200099184 (160007448) Time: 800 (2214766) Test4 Mem: 40091736/200099184 (160007448) Time: 506 (1400698) Test5 Mem: 40091736/300762224 (260670488) Time: 1436 (3975880) Test6 Mem: 40091736/300762232 (260670496) Time: 743 (2058002) Test1 Mem: 40091736/200099184 (160007448) Time: 482 (1335709) Test2 Mem: 40091736/200099184 (160007448) Time: 777 (2150719) Test3 Mem: 40091736/200099184 (160007448) Time: 793 (2196184) Test4 Mem: 40091736/200099184 (160007448) Time: 493 (1365222) Test5 Mem: 40091736/300762240 (260670504) Time: 1434 (3969530) Test6 Mem: 40091736/300762232 (260670496) Time: 746 (2064278)
Интересно, что ConvertAll()
выполняет те же действия, что и обычный цикл.
Ответ 2
Вы не можете наложить DateTime[]
на object[]
, потому что это будет небезопасно. Все массивы опорных типов одинаковой длины имеют одинаковый макет в памяти. DateTime - тип значения, а массив - "плоский" (unboxed). Вы не можете безопасно использовать object[]
, потому что макет в памяти несовместим с object[]
.
Ответ 3
Если у вас есть LINQ (.NET 3.5+), вы можете сделать:
DateTime[] dates = new DateTime[3];
dates[0] = new DateTime(2009, 01, 01);
dates[1] = new DateTime(2010, 01, 01);
dates[2] = new DateTime(2011, 01, 01);
object[] dates2 = Array.ConvertAll(dates, d => (object)d);
Как отметил Джефф, вы также можете сделать аналогичную вещь в .NET 2.0 с помощью делегатов:
object[] dates3 = Array.ConvertAll(dates,
delegate(DateTime d) { return (object)d; });
Ответ 4
Кстати, вы можете выполнить это, используя Array.Copy()
void Main()
{
DateTime[] dates = new DateTime[] { new DateTime(2000, 1, 1), new DateTime (2000, 3, 25) };
object[] objDates = new object[2];
Array.Copy(dates, objDates, 2);
foreach (object o in objDates) {
Console.WriteLine(o);
}
}
Ответ 5
Потому что DateTime
- a object
, но массив DateTime
не - массив object
.
Массивы типов значений отличаются от массивов ссылочных типов, поэтому эти два типа массивов принципиально несовместимы. Массив типа значения фактически содержит значения, и массив ссылочного типа содержит, ну, только ссылки.
Ответ 6
См. другие ответы, почему вы не можете этого сделать.
Альтернативой является выполнение глубокой копии массива. Пример использования LINQ:
DateTime[] dates = ...;
object[] objects = dates.Select(d => (object)d).ToArray();