2015-06-10 3 views
2

Я использую свой собственный метод расширения, чтобы сериализовать строки (и больше типов данных) в файл с пользовательским двоичным форматом (внешний, я не могу изменить этот формат). Мой метод:Как расширить строку для десериализации двоичных данных

public static byte[] Serialize(this string str) 
{ 
    if (str.Length > short.MaxValue) 
     throw new ArgumentOutOfRangeException("str", "Max length allowed is " + short.MaxValue.ToString()); 
    List<byte> data = new List<byte>(); 
    data.Add(0); 
    data.Add(0); 
    if (str != null) 
    { 
     byte[] buffer = Encoding.UTF8.GetBytes(str); 
     data.AddRange(buffer); 
     data[0] = (byte)(buffer.Length % 256); 
     data[1] = (byte)((buffer.Length/256) >> 8); 
    } 
    return data.ToArray(); 
} 

Пример использования:

string str1 = "Binary String"; 
byte[] data = str1.Serialize(); 

Результат

data = { 13, 0, 66, 105, 110, 97, 114, 121, 32, 83, 116, 114, 105, 110, 103 } 

Теперь я пытаюсь добавить еще один метод расширения для десериализации при чтении из этих файлов :

public static void Deserialize(this string str, byte[] data) 
{ 
    if (data == null || data.Length < 2) 
    { 
     str = null; 
    } 
    else 
    { 
     short length = (short)(data[0] + (data[1] << 8)); 
     if (data.Length != length + 2) 
      throw new ArgumentException("Invalid data", "data"); 
     str = Encoding.UTF8.GetString(data, 2, length); 
    } 
} 

Если я пытаюсь это:

string str2 = null; 
str2.Deserialize(data); 

Ожидаемый результат для str2 является

"Binary String"

Фактический результат

нуль

Однако при отладке шаг за шагом str внутри Deserialize() получает правильное значение по строке str = Encoding.UTF8.GetString(data, 2, length);.

также попытался это:

string str3 = string.Deserialize(data); 

Но он не компилируется, а сообщение об ошибке

Ошибка 1 'строка' не содержит определение для 'Deserialize'

Я не знаю, что я делаю неправильно. Любая идея о том, как ее решить?

+1

Вы просто не можете изменить str в методе. str должен быть выходным параметром, чтобы вывести его из метода. Но я уверен, что вы не можете определить параметр метода расширения как out. – Ralf

+1

Строки неизменяемы, но даже если вы пройдете класс, метод будет терпеть неудачу. Если вы не отметите параметр как 'out' или' ref', метод изменит копию исходного значения, которое затем будет выброшено. –

ответ

6

Первым параметром extension method является объект, над которым вы действуете. В этом случае это байтовый массив data. Тип возврата - это то, что вы хотите вложить в строковую переменную. Таким образом, сигнатура метода Deserialize должно быть:

public static string Deserialize(this byte[] data) 

Также внутри метода, необходимо вернуть значение строки, чтобы ваш полный метод должен быть (обратите внимание, что я упростил очень немного):

public static string Deserialize(this byte[] data) 
{ 
    if (data == null || data.Length < 2) 
     return null; 

    short length = (short)(data[0] + (data[1] << 8)); 
    if (data.Length != length + 2) 
     throw new ArgumentException("Invalid data", "data"); 

    return Encoding.UTF8.GetString(data, 2, length); 
} 

И использовать его как это:

string str1 = "Binary String"; 
byte[] data = str1.Serialize(); 
string str2 = data.Deserialize(); 
1

Хотя вариант DavidG является 100% правильно, я добавлю еще несколько объяснений. Елки всех, при вызове метода расширения на объекте, на самом деле статический метод будет вызывать вместо этого, так

str2.Deserialize(data); 

будет преобразован в

ClassThatContainsExtensionMethod.Deserialize(str2, data); 

Теперь давайте вспомним, что C# передает параметры по значению, это означает, что будет создана другая ссылка.

В вашем Deserialize() метода вы модифицирование новой строки, а не старшая (потому что это копия), когда вы делаете

str = Encoding.UTF8.GetString(data, 2, length); 

вы на самом деле изменить эту локальные ули, в то время как оригинал один остается неизменным (т.е. null).

FYK, вы можете передавать параметры методов по ссылке, используя ref и out ключевые слова.

BTW, вы действительно уверены, что достаточно двух байтов для длины?

+0

Да, эти файлы были написаны старой программой на C++, но, похоже, использует специальный метод сериализации. В противном случае я бы использовал 'BinaryReader.ReadString()'. –

+0

Увидев последнее предложение, я понял, что не проверял его в методе «Сериализация». Я добавил исправление. –