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

How to extend string to deserialize binary data

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

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"

实际结果是

null

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

也试过这个:

string str3 = string.Deserialize(data);

但是编译不通过,报错信息为

Error 1 'string' does not contain a definition for 'Deserialize'

我不知道我做错了什么。知道如何解决吗?

extension method 的第一个参数是您正在操作的对象。在本例中,它是字节数组 data。 return 类型是您想要填充到字符串变量中的内容。因此,Deserialize 方法的签名应该是:

public static string Deserialize(this byte[] data)

同样在方法内部,您需要 return 字符串值,因此您的完整方法应该是(请注意,我稍微简化了它):

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();

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

str2.Deserialize(data);

将转换为

ClassThatContainsExtensionMethod.Deserialize(str2, data);

现在让我们记住 C# 通过值传递参数,这意味着将创建另一个引用。

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

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

你实际上改变了这个本地字符串,而原来的字符串保持不变(即null)。

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

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