How to use Span in Convert.TryFromBase64String()?
Here's another approach, using ArrayPool, if you need the buffer only temporarily:
// Minimum length that is sure to fit all the data.
// We don't need to be 100% accurate here,
// because ArrayPool might return a larger buffer anyway.
var length = ((value.Length * 3) + 3) / 4;
var buffer = ArrayPool<byte>.Shared.Rent(length);
try
{
// (buffer is implicitly cast to Span<byte>)
if (Convert.TryFromBase64String(value, buffer, out var bytesWritten))
{
// do something with it...
return Encoding.UTF8.GetString(buffer, 0, bytesWritten);
}
throw new FormatException("Invalid base-64 sequence.");
}
finally
{
ArrayPool<byte>.Shared.Return(buffer);
}
You could use it like this, making use of all the TryFromBase64String
arguments:
public string DecodeUtf8Base64(string input)
{
var bytes = new Span<byte>(new byte[256]); // 256 is arbitrary
if (!Convert.TryFromBase64String(input, bytes, out var bytesWritten))
{
throw new InvalidOperationException("The input is not a valid base64 string");
}
return Encoding.UTF8.GetString(bytes.Slice(0, bytesWritten));
}
As written in the linked questions, System.Span<T>
is a new C# 7.2 feature (and the Convert.TryFromBase64String
is a newer .NET Core feature)
To use System.Span<>
you have to install a nuget package:
Install-Package System.Memory
Then to use it:
byte[] buffer = new byte[((b64string.Length * 3) + 3) / 4 -
(b64string.Length > 0 && b64string[b64string.Length - 1] == '=' ?
b64string.Length > 1 && b64string[b64string.Length - 2] == '=' ?
2 : 1 : 0)];
int written;
bool success = Convert.TryFromBase64String(b64string, buffer, out written);
Where b64string
is your base-64 string. The over-complicated size for buffer
should be the exact length of the buffer based on the length of the b64string
.