2

在 VB.NET 中,如果我想为不同类型的数值变量(Integer, Long, Decimal, Double)提供扩展方法,我总是必须为这些定义多个方法:

<Extension()> Public Function Add(a As Integer, b As Integer) As Integer
    Return a + b
End Function

<Extension()> Public Function Add(a As Long, b As Long) As Long
    Return a + b
End Function

<Extension()> Public Function Add(a As Double, b As Double) As Double
    Return a + b
End Function

<Extension()> Public Function Add(a As Decimal, b As Decimal) As Decimal
    Return a + b
End Function

现在对于一个单一的操作,这没问题,但是我想要创建的方法越多,我也需要做更多的重复。

有没有通用的方法呢?我很想看到这样的东西(伪代码):

<Extension()> _
Public Function Add(Of T As Numeric)(a As T, b As T) As T
    Return a + b
End Function

或者有没有其他概念可以这样做?

4

4 回答 4

2

这是无法做到的,因为您无法将泛型类型限制为一组数字类型(IntegerLongDecimalDouble)。问题是没有IArithmetic你可以用来约束T的接口,因此你不能这样写:

' This does not work because IArithmetic does not exist
<Extension()> _
Public Function Add(Of T As IArithmetic)(a As T, b As T) As T
    Return a + b
End Function

但是,您可以通过Microsoft 反馈中心加入这一事业,说服 Microsoft 实施此计划,并对类似请求提出建议和/或评论。

于 2013-08-07T13:34:22.933 回答
1

Jon Skeet 在通用运算符中使用 Operator<T> 解决了这个问题

public static class Operator
{
   public static T And<T>(T value1, T value2)
   {
      return Operator<T>.And(value1, value2);
   }
}

public static class Operator<T>
{
   public static Func<T, T, T> And { get { return and; } }
   static Operator()
   {
      add = ExpressionUtil.CreateExpression<T, T, T>(Expression.Add);
   }
}

@Jeroen Vannevel 对如何使用 T4 模板生成器方法来解决这个问题有一个很好的答案。 是否存在将我的泛型方法限制为数字类型的约束?

于 2014-09-18T17:22:53.180 回答
0

虽然这不是您正在寻找的内容,但您可能会发现它在此期间非常有用,可以节省大量输入:

Imports WindowsApplication2.Extensions

Public Module Extensions
    <Extension()>
    Public Function Add(A As Object, B As Object) As Object
        Dim numa, numb As Double
        Dim gooda As Boolean = Double.TryParse(A.ToString, numa)
        Dim goodb As Boolean = Double.TryParse(B.ToString, numb)
        Return numa + numb
    End Function
End Module

我在那里声明了 2 个布尔值,以防有人需要更强的错误检查。任何转换为​​字符串且无法解析为双精度的对象都将被视为 0。这样您也可以混合使用字符串、整数、双精度、长整数、浮点数等。我使用双精度,因为这似乎包含了大多数(如果不是)所有其他号码类型。当然,这很容易改变。

只需将返回值转换为您需要的任何类型。如果您打开了所有选项,Inellisense 会捕捉到这一点并提示您进行正确的投射

    Dim a As String = "5.0"
    Dim b As Double = CDbl(a.Add(2)) 

我知道这会冒犯一些情感,但就像我说的那样,它可能对某些人有用,作为权宜之计。

这是一篇有趣的文章。它是使用 C# 编写的,但您可能会发现这些概念也很有用。

于 2013-08-07T23:27:34.510 回答
0

受此答案的启发,以下似乎可行:

<Extension()> _
Public Function Add(Of T As {IConvertible, IComparable, IComparable(Of T), 
                             IFormattable, IEquatable(Of T)}) _
                   (a As T, b As T) As Decimal
    Return a.ToDecimal(Nothing) + b.ToDecimal(Nothing)
End Function

类型定义将扩展方法限制为接近数字类型。(但不是 100%,因为您仍然可以调用它ByteDate但这是不希望的。)

例子:

Dim dec As Decimal = Add(CDec(12.34), CDec(34.56))
Dim sng As Single = CSng(Add(CSng(34.56), CSng(45.67)))
Dim dbl As Double = CDbl(Add(CDbl(123.34), CDbl(45.123)))
Dim int As Integer = CInt(Add(CInt(12), CInt(34)))
Dim lng As Long = CLng(Add(CLng(1200), CLng(3400)))

拥有两个泛型类型还允许使用混合数字类型:

<Extension()> _
Public Function Add(Of T As {IConvertible, IComparable, IComparable(Of T), 
                             IFormattable, IEquatable(Of T)},
                       U As {IConvertible, IComparable, IComparable(Of U), 
                             IFormattable, IEquatable(Of U)}) _
                   (a As T, b As U) As Decimal
    Return a.ToDecimal(Nothing) + b.ToDecimal(Nothing)
End Function

例子:

Dim mixed As Decimal = Add(CDec(12.34), CSng(23.45))

我知道这仍然不理想,因为在转换为十进制或返回时可能会有一些损失。如果您不使用小数,这仍然需要转换函数的结果。但它确实避免了在许多情况下重复的需要。

于 2013-08-08T07:40:53.883 回答