如何使用泛型变量执行数学运算?

时间:2015-06-01 18:25:21

标签: c# .net generics types

我正在开发一个需要整数字符串表示的项目,但是使用.NET Framework本身不支持的奇数数字基础(据我所知) - 例如base36,62,64等。 /> 我们决定编写一个可以使用任何数字库的整体字符串转换系统,因为它足够简单。

稍后,我们想要创建一个自定义的IFormatProvider / ICustomFormatter,以便在旅途中更容易使用。
但首先,我们希望以一些静态方法的形式解决转换过程本身,这些方法执行转换并返回一些基本结果。
一旦我们开始工作,我们就会把IFormatProvider封装器放到位。

自从我使用C#generics以来已经有一段时间了,我不记得如何使编译器对此操作感到满意。
我更喜欢创建一个私有静态通用ConvertInteger方法,然后我可以从公共静态Convert方法调用它来帮助强制执行强类型操作,而不会使其使用起来很乱。
此设置的一个主要原因是在转换有符号值与无符号值时避免符号位出现问题 现在,我们为convertlong设置了公共静态ulong方法,以帮助避免签名和无符号值之间的转换问题。
在将来,假设我们可以使用私有静态泛型方法,我们希望将公共方法扩展为包括int,uint,short,ushort,byte和sbyte作为显式实现,以帮助执行此方法时的性能大批量不等整数值的方法 这是通用方法设计派上用场的地方,所以我们不必一遍又一遍地复制完全相同的代码(使测试和调试也变得更加简单)。

我遇到的问题是,编译器不允许我使用泛型类型执行比较或数学运算,因为它不知道如何在之前执行操作提供泛型类型参数值 (这主要是因为C ++开发人员让我很烦恼,因为C ++通过简单地避免尝试解释通用代码直到提供类型参数值之后的来解决这个问题。)

使用这种通用方法设计,我需要做些什么来满足编译器? 我已经提供了下面的代码,注释表明了特定的编译错误。

public static class NumericStringConverter
{
    private static readonly string[] StandardDigits = new string[]
    {
        "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
        "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
        "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
        "_", "-"
    };



    private static string ConvertInteger<T>(T Value, T Base)
    {
        if (Base < 2) // error here: "Operator '<' cannot be applied to operands of type 'T' and 'int'"
            throw new ArgumentOutOfRangeException("Base", Base, "The NumericStringConverter.Convert(Value, Base) method was called, with the Base parameter set to a value less than 2.");

        if (Base > 64) // error here: "Operator '>' cannot be applied to operands of type 'T' and 'int'"
            throw new ArgumentOutOfRangeException("Base", Base, "The NumericStringConverter.Convert(Value, Base) method was called, with the Base parameter set to a value greater than 64.");

        if (Value == 0) // error here: "Operator '==' cannot be applied to operands of type 'T' and 'int'"
            return StandardDigits[0];

        string strResult = "";
        bool IsValueNegative = (Value < 0); // error here: "Operator '<' cannot be applied to operands of type 'T' and 'int'"

        while (Value != 0) // error here: "Operator '!=' cannot be applied to operands of type 'T' and 'int'"
        {
            strResult = strResult.Insert(0, StandardDigits[Math.Abs(Value % Base)]); // error here: "Operator '%' cannot be applied to operands of type 'T' and 'T'"
            Value /= Base; // error here: "Operator '/=' cannot be applied to operands of type 'T' and 'T'"
        }

        if (IsValueNegative)
            strResult = strResult.Insert(0, "-");

        return strResult;
    }



    public static string Convert(long Value, long Base)
    {
        return ConvertInteger<long>(Value, Base);
    }

    public static string Convert(ulong Value, ulong Base)
    {
        return ConvertInteger<ulong>(Value, Base);
    }

    public static T Convert<T>(string Value, T Base)
    {
        return default(T); // TODO: convert a string back into an integer value.
    }
}

2 个答案:

答案 0 :(得分:4)

由于你不能定义只允许整数类型的通用约束,我只会有一个适用于this的方法和一个longs的重载:

int

答案 1 :(得分:0)

C# 10 和 .NET 6:2021 年 11 月以后的解决方案

好消息:现在在 .NET 6 和 C# 10 中有一个解决方案,参见。 https://devblogs.microsoft.com/dotnet/preview-features-in-net-6-generic-math/#generic-math

为了执行数学运算,您可以接受任何数字类型 INumber<T> 并指定所需的运算符,例如:

public T Adding<T>(T a, T b)
   where T : INumber<T>
   where T : IAdditionOperators<T, T, T>
{
   return a + b;
}

注意:在我回答时,此功能只是一个预览。微软将在 .NET 6 的最终版本中保留这一点,因为他们仍然希望允许打破机会。要使用该功能,必须在项目配置中启用预览功能:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <EnablePreviewFeatures>true</EnablePreviewFeatures>
    <LangVersion>preview</LangVersion>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="System.Runtime.Experimental" Version="6.0.0-preview.7.21377.19" />
  </ItemGroup>

</Project>