【问题标题】:How to pass a byte array readonly?如何以只读方式传递字节数组?
【发布时间】:2010-07-18 20:54:48
【问题描述】:

想想下面的代码:

static int Main() {
     byte[] data = File.ReadAllBytes("anyfile");
     SomeMethod(data);
     ...
}
static void SomeMethod(byte[] data) {
     data[0] = anybytevalue; // this line should not be possible!!!
     byte b = data[0];       // only reading should be allowed
     ...
}

有没有办法在 C# 中只读传递 byte[]?抄袭不是解决办法。我不想浪费内存(因为文件可能会变得非常大)。请牢记性能!

【问题讨论】:

  • C# 已经在您的标签中。请不要在您的标题中重复此内容。

标签: c# bytearray readonly readonly-collection


【解决方案1】:

你可以传递一个ReadOnlyCollection<byte>,像这样:

static int Main() {
     byte[] data = File.ReadAllBytes("anyfile");
     SomeMethod(new ReadOnlyCollection<byte>(data));
     ...
}
static void SomeMethod(ReadOnlyCollection<byte> data) {
     byte b = data[0];       // only reading is allowed
     ...
}

但是,最好传递Stream,如下所示:
这样,您根本不会将整个文件读入内存。

static int Main() {
     Stream file = File.OpenRead("anyfile");
     SomeMethod(file);
     ...
}
static void SomeMethod(Stream data) {
     byte b = data.ReadByte();       // only reading is allowed
     ...
}

【讨论】:

  • 使用 ReadOnlyCollection 代替数组时是否有任何性能差异?
  • @youllknow:无法衡量; ReadOnlyCollectionIList&lt;T&gt; 周围的薄包装。
  • @youllknow:正如 SLaks 所提到的,ReadOnlyCollection 实际上是 IList 的包装器。所以访问一个项目是一个方法调用一个接口调用。与访问数组中的单个字节的成本相比,这是非常昂贵的(比如要贵 20 倍)。如果您的数组很大,请务必对此进行分析!
  • @nikie,我做了一些测试,平均慢了大约 3.5 倍,而不是 20 倍......
  • @Thomas:你测试了什么?我测试了在循环中对 1.000.000 字节数组求和。数组:0.6 毫秒,ReadOnlyCollection:20 毫秒。这远远超过 3.5 倍
【解决方案2】:

我想这可能就是你要找的东西。

编译下面的代码,你会得到这个编译错误:Property or indexer 'Stack2.MyReadOnlyBytes.this[int]' cannot be assigned to -- it is read only

public class MyReadOnlyBytes
{
   private byte[] myData;

   public MyReadOnlyBytes(byte[] data)
   {
      myData = data;
   }

   public byte this[int i]
   {
      get
      {
         return myData[i];
      }
   }
}

class Program
{
   static void Main(string[] args)
   {
      var b = File.ReadAllBytes(@"C:\Windows\explorer.exe");
      var myb = new MyReadOnlyBytes(b);

      Test(myb);

      Console.ReadLine();
   }

   private static void Test(MyReadOnlyBytes myb)
   {
      Console.WriteLine(myb[0]);
      myb[0] = myb[1];
      Console.WriteLine(myb[0]);
   }
}

【讨论】:

  • 我认为最好的解决方案。谢谢。
【解决方案3】:

我建议您在完成这项工作的层次结构中使用尽可能高的对象。在您的情况下,这将是 IEnumerable&lt;byte&gt;:

static int Main() 
{
     byte[] data = File.ReadAllBytes("anyfile");
     SomeMethod(data);
}

static void SomeMethod(IEnumerable<byte> data)
{
    byte b = data.ElementAt(0); 
    // Notice that the ElementAt extension method is sufficiently intelligent
    // to use the indexer in this case instead of creating an enumerator
}

【讨论】:

  • ((byte[])data)[0] = anybytevalue;
  • @Slaks,当然是选角,但无论你尝试什么,总会有办法规避这一点。例如反射。因此,即使使用ReadOnlyCollection&lt;byte&gt;,用户也能够修改原始字节结构(尽管他需要编写比简单转换更多的代码)。我假设 OP 在这里寻找编译时安全而不是运行时。
  • 好吧,您可以使用 Enumerable.ToList 创建数据的副本。没有办法通过演员或反射来规避这一点。不过,我不会推荐它。
猜你喜欢
  • 1970-01-01
  • 2015-02-27
  • 2012-08-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-07
  • 2018-09-24
  • 2015-11-25
相关资源
最近更新 更多