【问题标题】:c# use a generic function to pass parameter to a function with many overloadsc#使用泛型函数将参数传递给具有许多重载的函数
【发布时间】:2016-11-08 07:16:28
【问题描述】:

我正在尝试创建以下函数:

    public static byte[] ValueToBigEndian<T>(T data)
    {
        byte[] bytes;
        // We want to use big endian
        if (BitConverter.IsLittleEndian)
        {
            bytes = BitConverter.GetBytes(data).Reverse().ToArray();
            //bytes.Take(System.Runtime.InteropServices.Marshal.SizeOf(data)); // probabl don't need this
        }
        else
        {
            // Host is big endian already
            bytes = BitConverter.GetBytes(data;
            //bytes.Take(System.Runtime.InteropServices.Marshal.SizeOf(data)); // probabl don't need this
        }

        return bytes;
    }

所以我在这里使用BitConverter.GetBytes(...),它不是通用的,但它有很多重载(ushortintboolulonglongshort 等... )。

我试图避免为每一个编写匹配的重载函数,所以我的想法是使用泛型函数。恕我直言,这将运行良好,直到有人尝试使用不在重载列表中的类型,然后编译器会抱怨。但是编译器会立即抱怨,因为T 类型没有重载。

我得到的错误是

错误 CS1503 参数 1:无法从 'T' 转换为 'bool'

有没有办法实现我在这里尝试的目标?

【问题讨论】:

  • 您不能这样做,编译器需要知道T 可以是什么,以便解析对GetBytes 的调用。由于T 可以是任何类型(来自签名),object 或任何其他类型也是可能的,而GetBytes 没有这样的重载。所以我想你想做的事情是不可能的,你被困在使用重载上。

标签: c# templates generics


【解决方案1】:

你得到这个的原因是因为值类型不能被模板化。就个人而言,我认为这是 C# 的失败,并且总是会导致重复,尽管开发人员对此有什么看法。

您所能做的就是为每个值类型创建重载...

更新

另一种更肮脏的方法是通过反射来解决这个问题。您实际上可以通过这样做获得所需的方法:

    public static byte[] GetBytesTemplated<T>(T value) where T : struct
    {
        var method = typeof(BitConverter).GetMethod("GetBytes", new[]{typeof(T)});
        return (byte[])method.Invoke(null, new object[]{value});
    }

但是,这样您需要自己检查模板的值类型。 您的最终代码将如下所示:

public static byte[] ValueToBigEndian<T>(T data) where T : struct
{
    byte[] bytes = GetBytesTemplated(data);
    // We want to use big endian
    if (BitConverter.IsLittleEndian)
    {
        Array.Reverse(bytes);
    }
    return bytes;
}

【讨论】:

  • 将约束 where T : struct 与反射相结合可能是最好的方法 - 因为 GetBytes 的所有重载都采用值类型。该约束至少提供了的编译时保护。
【解决方案2】:

逻辑会声明这是可以做到的。但是,所有值类型都继承自 BitConverter.GetBytes 的任何重载都不会接受作为参数的公共类型(Object 除外)。

您可以做的一件事是改用泛型参数,并相信传递给方法的值是BitConverter.GetBytes 的有效参数类型之一:

public static byte[] ValueToBigEndian(dynamic data)
{
    byte[] bytes = BitConverter.GetBytes(data);

    if (BitConverter.IsLittleEndian)
        Array.Reverse(bytes);

    return bytes;
}

与使用反射相比,我更喜欢这种方法,因为它更容易理解正在发生的事情,而且我相信它也会运行得更快(未经测试的声明)。但是,与反射一样,您必须进行自己的类型检查以捕捉传递不兼容类型的对象的情况。 (这可以通过 try-catch 来处理,但我不确定这是否一定会被视为“最佳实践”。)

【讨论】:

  • 效果很好,简单易行:) - 不确定它是否有任何问题,我还没有尝试传递对象(希望得到编译器错误),当我更新时试试这个。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多