为什么我不能将日期时间 [] 强制转换为对象 []

本文关键字:转换 对象 日期 时间 为什么 不能 | 更新日期: 2023-09-27 17:56:31

似乎我可以将日期时间强制转换为对象,那么为什么我不能将数组 DateTime[] 转换为对象[]? 我知道这与值/引用类型有关,但装箱不允许我这样做吗?

为什么我不能将日期时间 [] 强制转换为对象 []

数组协方差仅适用于引用类型的数组。 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, 酷睿2四核 Q9550@2.83GHz, 4GiB DDR2 1066 (PC2-8500)
64 位构建(32 位大致相同,只是总体内存更少)

测试1内存:40086256/200087360(160001104)        时间: 444 (1230723)测试2内存:40091352/200099272(160007920)        时间: 751 (2078001)测试3内存:40091416/200099256(160007840)        时间: 800 (2213764)测试4内存:40091480/200099256(160007776)        时间: 490 (1358326)测试5内存:40091608/300762328(260670720)        时间: 1407 (3893922)测试6 内存: 40091672/300762328 (260670656)        时间: 756 (2092566)测试1 内存: 40091736/200099184 (160007448)        时间: 515 (1425098)测试2内存: 40091736/200099184 (160007448)        时间: 868 (2404151)测试3 内存: 40091736/200099160 (160007424)        时间: 885 (2448850)测试4内存:40091736/200099184(160007448)        时间: 540 (1494429)测试5内存:40091736/300762240(260670504)        时间: 1479 (4093676)测试6 内存: 40091736/300762216 (260670480)        时间: 746 (2065095)测试1 内存: 40091736/200099168 (160007432)        时间: 500 (1383656)测试2内存:40091736/200099160(160007424)        时间: 781 (2162711)测试3 内存: 40091736/200099176 (160007440)        时间: 793 (2194605)测试4内存:40091736/200099184(160007448)        时间: 486 (1346549)测试5内存:40091736/300762232(260670496)        时间: 1448 (4008145)测试6 内存: 40091736/300762232 (260670496)        时间: 749 (2075019)测试1 内存: 40091736/200099184 (160007448)        时间: 487 (1349320)测试2内存:40091736/200099176(160007440)        时间: 781 (2162729)测试3内存:40091736/200099184(160007448)        时间: 800 (2214766)测试4内存:40091736/200099184(160007448)        时间: 506 (1400698)测试5 内存: 40091736/300762224 (260670488)        时间: 1436 (3975880)测试6 内存: 40091736/300762232 (260670496)        时间: 743 (2058002)测试1 内存: 40091736/200099184 (160007448)        时间: 482 (1335709)测试2内存: 40091736/200099184 (160007448)        时间: 777 (2150719)测试3内存:40091736/200099184(160007448)        时间: 793 (2196184)测试4内存:40091736/200099184(160007448)        时间: 493 (1365222)测试5内存:40091736/300762240(260670504)        时间: 1434 (3969530)测试6 内存: 40091736/300762232 (260670496)        时间: 746 (2064278)

有趣的是,ConvertAll() 的性能与普通循环大致相同。

您不能将DateTime[]投射到object[],因为这不安全。相同长度的引用类型的所有数组在内存中具有相同的布局。日期时间是值类型,数组是"平面"(未装箱)。您无法安全地投射到 object[],因为内存中的布局与 object[] 不兼容。

如果您有可用的 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);

正如 Jeff 指出的那样,您也可以使用委托在 .NET 2.0 中执行类似操作:

object[] dates3 = Array.ConvertAll(dates, 
                        delegate(DateTime d) { return (object)d; });

因为DateTime是一个object,但DateTime数组不是object数组。

值类型的数组

与引用类型的数组不同,因此这两种类型的数组从根本上是不兼容的。 值类型数组实际上包含值,引用类型数组仅包含引用。

请参阅其他答案,了解为什么您不能这样做。

另一种方法是执行阵列的深层拷贝。使用 LINQ 的示例:

DateTime[] dates = ...;
object[] objects = dates.Select(d => (object)d).ToArray();

顺便说一句,你可以使用 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);
    }
}