通用扩展方法类型推断

dow*_*rme 1 c# generics extension-methods

我有一个扩展方法,可以将数值类型 A 的数组转换为数值类型 B 的数组

\n
public static T2[] ConvertTo<T1, T2>(this T1[] buffer)\n{\n    var bufferNumBytes = buffer.Length * Marshal.SizeOf(default(T1));\n    var targetElementNumBytes = Marshal.SizeOf(default(T2));\n    if (bufferNumBytes % targetElementNumBytes != 0)\n    {\n        throw new ArgumentException($"Array must have multiple of {targetElementNumBytes} bytes, has {bufferNumBytes} bytes instead", nameof(buffer));\n    }\n    var res = new T2[bufferNumBytes / targetElementNumBytes];\n    Buffer.BlockCopy(buffer, 0, res, 0, bufferNumBytes);\n    return res;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

我可以这样称呼它

\n
    var b = new ushort[] { 1, 256 };\n    var us = b.ConvertTo<ushort, byte>();\n\n    Assert.That(us[0], Is.EqualTo(1));\n    Assert.That(us[1], Is.EqualTo(0));\n    Assert.That(us[2], Is.EqualTo(0));\n    Assert.That(us[3], Is.EqualTo(1));\n
Run Code Online (Sandbox Code Playgroud)\n

然而,那个 T1 参数似乎是多余的,但我不\xc2\xb4t 知道如何摆脱它。\n一个解决方法是更通用的扩展方法

\n
public static T1[] ConvertTo<T1>(this byte[] buffer)\n{\n    return buffer.ConvertTo<byte, T1>();\n}\n\npublic static T1[] ConvertTo<T1>(this sbyte[] buffer)\n{\n    return buffer.ConvertTo<sbyte, T1>();\n}\n\npublic static T1[] ConvertTo<T1>(this ushort[] buffer)\n{\n    return buffer.ConvertTo<ushort, T1>();\n}\n...\n
Run Code Online (Sandbox Code Playgroud)\n

但我更喜欢一种更简单的方法,只有一个参数(目标类型),编译器自行推断缓冲区的类型。

\n

RB.*_*RB. 5

您可以通过使用流畅的界面获得您想要的大部分内容:

void Main()
{
    var b = new ushort[] { 1, 256 };

    // We now use a fluent interface to do the conversion - T1 is
    // now inferred.
    var us = b.Convert().To<byte>();
    
    us.Dump();
}

public static class Extensions
{
    public static IConverter Convert<T1>(this T1[] buffer)
    {
        return new Converter<T1>(buffer);
    }
}

public interface IConverter
{
    T2[] To<T2>();
}

public class Converter<T1> : IConverter
{
    private readonly T1[] _buffer;
    public Converter(T1[] buffer)
    {
        _buffer = buffer ?? throw new ArgumentNullException();
    }
    
    public T2[] To<T2>()
    {
        var bufferNumBytes = _buffer.Length * Marshal.SizeOf(default(T1));
        var targetElementNumBytes = Marshal.SizeOf(default(T2));
        if (bufferNumBytes % targetElementNumBytes != 0)
        {
            throw new ArgumentException($"Array must have multiple of {targetElementNumBytes} bytes, has {bufferNumBytes} bytes instead", nameof(_buffer));
        }
        var res = new T2[bufferNumBytes / targetElementNumBytes];
        Buffer.BlockCopy(_buffer, 0, res, 0, bufferNumBytes);
        return res;
    }
}
Run Code Online (Sandbox Code Playgroud)

缺点是您为类分配了额外的内存Converter,并且最终调用了两个方法 - 但可发现性应该基本上与您原来的示例一样好,我认为这才是真正激发您的问题的原因。