如何扩展字符串以反序列化二进制数据

时间:2015-06-10 15:15:59

标签: c# extension-methods

我使用自己的扩展方法将字符串(和更多数据类型)序列化为具有自定义二进制格式的文件(外部,我无法修改该格式)。 我的方法是:

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的预期结果是

  

&#34;二进制字符串&#34;

实际结果是

  

但是,在逐步调试时,str内的Deserialize()会在第str = Encoding.UTF8.GetString(data, 2, length);行获得正确的值。

还试过这个:

string str3 = string.Deserialize(data);

但它没有编译,错误信息是

  

错误1&#39;字符串&#39;不包含&#39;反序列化&#39;

的定义

我不知道自己做错了什么。关于如何解决它的任何想法?

2 个答案:

答案 0 :(得分: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 :(得分:1)

虽然DavidG的变体100%正确,但我会添加更多解释。 首先,当你在一个对象上调用扩展方法时,实际上会调用一个静态方法,所以

str2.Deserialize(data);

将转换为

ClassThatContainsExtensionMethod.Deserialize(str2, data);

现在让我们记住C#按参数传递参数,这意味着将创建另一个参考。

在您的Deserialize()方法中修改新字符串,而不是旧字符串(因为它是副本),当您执行

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

你实际上改变了这个局部str,而原始的str保持不变(即null)。

FYK,您可以使用refout关键字通过引用传递方法参数。

顺便说一句,你确定,两个字节的长度足够吗?