是否有可能在.NET中编写只接受数字类型的泛型函数?

时间:2009-06-04 13:44:58

标签: .net vb.net generics types

假设我想编写一个类似下面的函数(像往常一样,这是一个简单的例子用于说明目的):

Public Function calcSqSum(Of T)(ByVal list As IEnumerable(Of T)) As T
    Dim sumSq As T

    For Each item As T In list
        sumSq += (item * item)
    Next

    Return sumSq
End Function

正如您可能猜到的,此函数会导致错误,因为无法保证通用对象实现+运算符。据我所知,任何数字类型(整数,双数,十进制等)都会。

有没有办法编写一个(quasi-)泛型函数,可以接受任何数字类型,而不必自己为每个这样的类型显式地重载函数?

或者,我认为同样可接受的解决方案是以某种方式检查类型是否实现'+'运算符(或通常与数字类型相关并由函数使用的任何运算符)。

5 个答案:

答案 0 :(得分:8)

不,因为没有特定的通用接口,所有这些接口都会实现。从本质上讲,框架中没有“数字类型”的真实概念。除非你将它们包装在自定义的类中,并且你的方法只接受你的类型(这不是你问题的直接答案,只是一种解决方法)。

答案 1 :(得分:1)

很抱歉,除非您创建自己的号码,否则不能。

public static T Add<T> (T x, T y) where T: MyNumberClass
{ 
// your add code
...
}

原因是.NET只允许您使用类或接口约束泛型方法。

答案 2 :(得分:1)

您可以使用lambda表达式,如下所示:

        static T Add<T>(T a, T b)
    {
        // declare the parameters
        ParameterExpression paramA = Expression.Parameter(typeof(T), "a"),
            paramB = Expression.Parameter(typeof(T), "b");
        // add the parameters together
        BinaryExpression body = Expression.Add(paramA, paramB);
        // compile it
        Func<T, T, T> add = Expression.Lambda<Func<T, T, T>>(body, paramA, paramB).Compile();
        // call it
        return add(a, b);
    }

它不是类型安全的,但它适用于具有预期运算符的类型(在上例中添加)。

答案 3 :(得分:1)

您可以使用重载。要为要支持的每种数字类型编写一个基本相同的函数:

Public Function calcSqSum(ByVal list As IEnumerable(Of Integer)) As Integer
    Dim sumSq As Integer
    For Each item As Integer In list
        sumSq += (item * item)
    Next
    Return sumSq
End Function

Public Function calcSqSum(ByVal list As IEnumerable(Of Double)) As Double
    Dim sumSq As Double
    For Each item As Double In list
        sumSq += (item * item)
    Next
    Return sumSq
End Function

etc

或者,如果其中包含大量代码,请将您的泛型函数设为私有,并使用重载公共函数进行包装:

Private Function calcSqSum1(Of T)(ByVal list As IEnumerable(Of T)) As T
    Dim sumSq As T

    For Each item As T In list
        sumSq += (item * item)
    Next

    Return sumSq
End Function

Public Function calcSqSum(ByVal list As IEnumerable(Of Integer)) As Integer
    Return calcSqSum1(list)
End Function

Public Function calcSqSum(ByVal list As IEnumerable(Of Double)) As Double
    Return calcSqSum1(list)
End Function

etc

这不是你想要的,但公共功能将是类型安全的。

答案 4 :(得分: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

我目前无法估计此功能是否也可以在 VB.NET 中使用。

为了接受任何数字类型,请使用 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>