2010-07-18 2 views
2

Придумайте следующий код:Как передать байтовый массив readonly?

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 
    ... 
} 

Есть ли способ чтения прохождения Byte [] в C#? Копирование не является решением. Мне не хотелось бы тратить память (потому что файл может стать очень большим). Помните о производительности!

+0

C# уже в ваших тегах. Пожалуйста, не дублируйте это в своем названии. –

+0

Извините, я не знал! – raisyn

ответ

11

Вы можете передать 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 
    ... 
} 
+0

Существуют ли различия в производительности при использовании ReadOnlyCollection вместо массива? – raisyn

+0

@youllknow: Не измеримо; 'ReadOnlyCollection' - это тонкая оболочка вокруг' IList '. – SLaks

+0

@youllknow: Как упоминалось в SLaks, ReadOnlyCollection на самом деле является оберткой вокруг IList . Таким образом, доступ к элементу - вызов метода * и * вызов интерфейса. Это очень дорого, по сравнению со стоимостью доступа к одному байту в массиве (например, в 20 раз дороже). Если ваш массив большой, обязательно профайл! – Niki

2

Я бы порекомендовал вам использовать максимально возможный объект в иерархии, выполняющей задание. В вашем случае это будет IEnumerable<byte>:

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 
} 
+0

'((byte []) data) [0] = anybytevalue;' – SLaks

+2

@Slaks, уверенное кастинг, но независимо от того, что вы пытаетесь, всегда будут способы обойти это. Например, отражение. Таким образом, даже с помощью 'ReadOnlyCollection ' пользователь сможет модифицировать исходную структуру байтов (хотя ему нужно будет написать немного больше кода, чем просто кастинг). Я предположил, что OP ищет безопасность времени компиляции, а не время выполнения. –

+0

Ну, вы * можете * создать копию данных с помощью Enumerable.ToList. Невозможно обойти это с помощью броска или отражения. Я бы не рекомендовал его. – Niki

4

Я думаю, что это может быть то, что вы ищете.

Скомпилировать ниже, и вы получите эту ошибку компиляции: Свойство или индексатор «Stack2.MyReadOnlyBytes.this [INT]» не может быть назначен - это только для чтения

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]); 
    } 
} 
+0

хорошее решение тоже! вы сделали какие-либо сравнения скорости? – raisyn

+0

не производили скорость comps –

+0

Лучшее решение на мой взгляд. Thanx. – Darkonekt