将字节数组初始化为某个值,而不是默认的null?

DeV*_*Vil 152 .net c# arrays initialization

我正在忙着用C++重写一个用C#完成的旧项目.

我的任务是重写程序,使其尽可能接近原始程序.

在一堆文件处理期间,编写该程序的前一个开发人员创建了一个包含大量字段的结构,这些字段对应于必须写入文件的设置格式,因此所有这些工作都已经完成.

这些字段都是字节数组.然后C++代码memset用来将整个结构设置为所有空格字符(0x20).一行代码.简单.

这非常重要,因为该文件最终会使用这种格式的文件.我必须做的是将此结构更改为C#中的类,但我找不到一种方法可以轻松地将每个字节数组初始化为所有空格字符.

我最终要做的是在类构造函数中:

//Initialize all of the variables to spaces.
int index = 0;
foreach (byte b in UserCode)
{
    UserCode[index] = 0x20;
    index++;
}
Run Code Online (Sandbox Code Playgroud)

这很好,但我确信必须有一个更简单的方法来做到这一点.当数组UserCode = new byte[6]在构造函数中设置为时,字节数组会自动初始化为默认的空值.是否有办法让它在声明时变成所有空格,所以当我调用我的类'构造函数时,它会像这样直接初始化?或者memset类似功能?

Luk*_*keH 182

对于小型数组,使用数组初始化语法:

var sevenItems = new byte[] { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 };
Run Code Online (Sandbox Code Playgroud)

对于较大的阵列,使用标准for循环.这是最可读和最有效的方法:

var sevenThousandItems = new byte[7000];
for (int i = 0; i < sevenThousandItems.Length; i++)
{
    sevenThousandItems[i] = 0x20;
}
Run Code Online (Sandbox Code Playgroud)

当然,如果你需要做很多事情,那么你可以创建一个帮助方法来帮助保持你的代码简洁:

byte[] sevenItems = CreateSpecialByteArray(7);
byte[] sevenThousandItems = CreateSpecialByteArray(7000);

// ...

public static byte[] CreateSpecialByteArray(int length)
{
    var arr = new byte[length];
    for (int i = 0; i < arr.Length; i++)
    {
        arr[i] = 0x20;
    }
    return arr;
}
Run Code Online (Sandbox Code Playgroud)

  • 您也可以将其转换为扩展方法.这样你就可以把它称为`byte [] b = new byte [5000] .Initialize(0x20);`扩展方法将被声明为`public static byte [] Initialize(this byte [] array,byte defaultValue)`并包含for循环.它应该返回数组. (6认同)
  • @advocate:初始化```new byte {4,3,2}```缺少方括号```[]```来声明一个数组.此外,你的常量需要转换为```byte```,其中数字(```int```s)如4,3和2不是.所以它必须是:```new byte [] {(byte)4,(byte)3,(byte)2}```,或十六进制语法. (4认同)
  • for 循环应该使用递减操作。我做了大量的基准测试,当主体只有一个简单的指令(例如填充数组元素)时,递减 for 循环通常比递增 for 循环快两倍。 (2认同)

Tho*_*mar 91

用它来创建数组:

byte[] array = Enumerable.Repeat((byte)0x20, <number of elements>).ToArray();
Run Code Online (Sandbox Code Playgroud)

替换<number of elements>为所需的阵列大小.

  • 这不如OP的原始解决方案.这仍然涉及在单独的步骤中创建和填充阵列.实际上,它通常最终会创建,填充然后丢弃几个(可能很多)中间数组,而不是仅分配单个数组然后填充它. (4认同)
  • 有趣的是,@ PompolutZ发现http://stackoverflow.com/questions/1897555/what-is-the-equivalent-of-memset-in-c的问题表明这不如循环那么有效因为这不仅仅是设置一些值.它可能更简单(这是被问到的)但我不知道这意味着更好.:)如果相关,总是测试性能.;-) (3认同)

Yoc*_*mer 31

你可以使用Enumerable.Repeat()

初始化为0x20的100个项目的数组:

byte[] arr1 = Enumerable.Repeat(0x20,100).ToArray();
Run Code Online (Sandbox Code Playgroud)

  • Enumerable.Repeat()返回一个IEnumerable,因此需要显式调用ToArray(). (4认同)
  • 还需要将要重复的元素转换为“byte”以获取 Byte 数组,而不是在本例中出现的“Int32”数组。又名 `byte[] arr1 = Enumerable.Repeat((byte)0x20, 100).ToArray();` (2认同)

Yur*_*kiy 30

var array = Encoding.ASCII.GetBytes(new string(' ', 100));
Run Code Online (Sandbox Code Playgroud)

  • +1 ......起初看起来很迂回,但实际上是迄今为止发布的所有内容中最自我记录的代码. (2认同)
  • @Neil:实际上,您的问题没有答案,因为new string()不会产生空终止符(.NET可以看到)。在.NET中,我们无需考虑,也不必担心。根本不在那里。 (2认同)

Dar*_*mas 9

如果需要初始化一个小数组,可以使用:

byte[] smallArray = new byte[] { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 };
Run Code Online (Sandbox Code Playgroud)

如果你有一个更大的数组,那么你可以使用:

byte[] bitBiggerArray Enumerable.Repeat(0x20, 7000).ToArray();
Run Code Online (Sandbox Code Playgroud)

这很简单,也很容易让下一个男/女孩阅读.并且99.9%的时间足够快.(通常是BestOption™)

但是,如果你真的需要超级速度,那么使用P/invoke调用优化的memset方法是适合你的:(这里包含在一个很好用的类中)

public static class Superfast
{
    [DllImport("msvcrt.dll",
              EntryPoint = "memset",
              CallingConvention = CallingConvention.Cdecl,
              SetLastError = false)]
    private static extern IntPtr MemSet(IntPtr dest, int c, int count);

    //If you need super speed, calling out to M$ memset optimized method using P/invoke
    public static byte[] InitByteArray(byte fillWith, int size)
    {
        byte[] arrayBytes = new byte[size];
        GCHandle gch = GCHandle.Alloc(arrayBytes, GCHandleType.Pinned);
        MemSet(gch.AddrOfPinnedObject(), fillWith, arrayBytes.Length);
        return arrayBytes;
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

byte[] oneofManyBigArrays =  Superfast.InitByteArray(0x20,700000);
Run Code Online (Sandbox Code Playgroud)


gwi*_*rrr 5

在我之前的人已经给了你答案。我只想指出你对 foreach 循环的误用。看,由于您必须增加索引标准,“for 循环”不仅更紧凑,而且效率更高(“foreach”在幕后做了很多事情):

for (int index = 0; index < UserCode.Length; ++index)
{
    UserCode[index] = 0x20;
}
Run Code Online (Sandbox Code Playgroud)


dee*_*gee 5

这是标记为答案的帖子中代码的更快版本。

我执行的所有基准测试都表明,一个只包含数组填充之类的简单for 循环如果它是递减的,那么它的速度通常是递增的两倍

此外,数组 Length 属性已经作为参数传递,因此不需要从数组属性中检索它。它还应该预先计算并分配给局部变量。涉及属性访问器的循环边界计算将在每次循环迭代之前重新计算边界值。

public static byte[] CreateSpecialByteArray(int length)
{
    byte[] array = new byte[length];

    int len = length - 1;

    for (int i = len; i >= 0; i--)
    {
        array[i] = 0x20;
    }

    return array;
}
Run Code Online (Sandbox Code Playgroud)