c# - 将可空数组复制到相同基类型的非可空数组的有效方法?

标签 c# arrays nullable

假设源数组保证没有任何可空值(如果它有,可以抛出异常)?显然,我可以遍历索引并单独复制每个元素。

这是行不通的。它编译,但抛出 byte?[]在运行时。

 byte?[] sourceNullable = new byte?[]{1,2,3};
 byte[] destNonNullable = new byte[3];

 Array.Copy(sourceNullable,destNonNullable,3);

这会起作用,但我正在寻找“更好”的东西

for(int i=0;i<3;i++) {
    destNonNullable[i] = sourceNullable[i] ?? 0;
}

我愿意接受答案:显式循环有什么问题?你为什么要浪费时间优化这个? :)


编辑:我尝试使用 Linq 样式 byte[] ,但事实证明这要慢得多。我的代码中的时间摘要如下:

for loop = 585 ms

Linq Cast = 3626 ms

输入ArrayTypeMismatchException文件是一个稀疏数组,其中填充了空值部分。

        uint rowsize = 16;
        Stopwatch sw = new Stopwatch();
        sw.Start();
        for (UInt32 address = start & 0xFFFFFFF0; address <= last; address += rowsize)
        {
            Int32 imageOffset = (Int32)(address - start);
            Int32 maxRowLen = (int)rowsize;
            if (maxRowLen + imageOffset > image.Length) maxRowLen = (image.Length - imageOffset);

            if (maxRowLen == 0) throw new Exception("this should not happen");

            int ptr = 0;
            while (ptr < maxRowLen)
            {
                while (ptr < maxRowLen && image[imageOffset + ptr] == null) ptr++;
                int startOffset = ptr;
                while (ptr < maxRowLen && image[imageOffset + ptr] != null) ptr++;
                int stopOffset = ptr;

                if (startOffset < maxRowLen)
                {
 #if false
                    int n = stopOffset - startOffset;
                    byte[] subdata = new byte[n];
                    for (int i = 0; i < n; i++)
                    {
                        subdata[i] = image[imageOffset + startOffset + i] ?? 0;
                    }
 #else
                    byte[] subdata = image.Skip(imageOffset + startOffset).Take(stopOffset - startOffset).Cast<byte>().ToArray();
 #endif
                    IntelHexRecord rec = new IntelHexRecord((uint)(address + startOffset), subdata);
                    records.Add(rec);
                }
            }
        }
        sw.Stop();
        Console.WriteLine("elapsed: {0} ms", sw.ElapsedMilliseconds);

最佳答案

您可以像这样使用 LINQ:

byte[] destNonNullable = sourceNullable.Cast<byte>().ToArray();

但是,这并不比您正在做的快。如果您需要一种更快的方法来复制编译时已知的固定数量的字节,则可以消除循环开销,这不是那么大,但如果您必须从中挤出最后一个 CPU 周期,则应该可行:

byte[] destNonNullable = new[] {
    sourceNullable[0].Value
,   sourceNullable[1].Value
,   sourceNullable[2].Value
};

您还可以通过 unwinding the loop 减少开销.例如,如果您知道要复制的字节数可以被四整除,您可以这样做:

Debug.Assert(N % 4 == 0); // Otherwise, the loop below wouldn't stop
for (int i = 0 ; i != N ; i += 4) {
    destNonNullable[i] = sourceNullable[i].Value;
    destNonNullable[i+1] = sourceNullable[i+1].Value;
    destNonNullable[i+2] = sourceNullable[i+2].Value;
    destNonNullable[i+3] = sourceNullable[i+3].Value;
}

关于c# - 将可空数组复制到相同基类型的非可空数组的有效方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17890181/

相关文章:

c# - NHibernate 左外连接名称到地址

java - java 统计元素出现的频率

java - 为什么基元不能为空

c# - C# 可空类型的编码实践

c# - 无法读取 cookie

C# Excel Reader 将时间戳转为十进制数

c# - 面板滚动 c#

c++ - 通过数组移动指针 - 通过引用或递增传递?

将莫尔斯字符串转换为字符数组

javascript - 如何编写可为空的完整属性