为什么C#允许在具有约束INumber的泛型类中使用+运算符,而VB.NET不允许?

huangapple go评论103阅读模式
英文:

Why does C# allow the usage of the + operator in generic classes with constrain INumber while VB.NET doesn't?

问题

首先,我目前正在使用VB.NET进行工作,因此对C#并不是很了解。

我想创建一个自定义的通用向量类,要求类型参数必须实现接口INumber(Of T)。然而,当我尝试在该类中声明一个**+-运算符**(使用两个向量给出的值进行逐元素相加)时,我的VB.NET项目产生了以下错误:

>
> 错误 BC30452:类型'T'和'T'之间未定义运算符'+'。
>
由于我几乎只测试了此页面上给出的示例,并且并不真正相信微软会发布一些不起作用的东西,所以我决定在C#中也测试一下我的问题(同样使用.NET 7)。

为此,我在VB.NET中构建了以下两个最小工作示例(MWE):

Vector.vb:

Imports System.Numerics


Public Class Vector(Of T As INumber(Of T))

    Private _items() As T

    Public Sub New(n As Integer)
        ReDim _items(n - 1)
    End Sub

    Public ReadOnly Property Size As Integer
        Get
            Return _items.Length
        End Get
    End Property

    Public Function GetValue(i As Integer) As T
        Return _items(i)
    End Function

    Public Sub SetValue(i As Integer, val As T)
        _items(i) = val
    End Sub

    Public Sub SetAll(val As T)
        For i As Integer = 0 To _items.Length - 1
            _items(i) = val
        Next
    End Sub

    Public Sub Print()
        For i As Integer = 0 To _items.Length - 1
            Console.WriteLine(_items(i))
        Next
    End Sub

    Public Shared Operator +(a As Vector(Of T), b As Vector(Of T)) As Vector(Of T)
        Dim retVal As New Vector(Of T)(a.Size)
        For i As Integer = 0 To retVal.Size - 1
            retVal.SetValue(i, a.GetValue(i) + b.GetValue(i))
        Next
        Return retVal
    End Operator

End Class

Program.vb:

Module Program
    Sub Main(args As String())
        Dim x As New Vector(Of Double)(3)
        x.SetAll(3)
        Dim y As New Vector(Of Double)(3)
        y.SetAll(2)
        Dim z = x + y
        z.Print()
    End Sub
End Module

<br>
<br>

以及在**C#**中

Vector.cs:

using System.Numerics;


namespace Test
{
    public class Vector<T> where T : INumber<T>
    {
        private T[] _items;

        public Vector(int n) {
            Array.Resize<T>(ref _items, n);
        }
        public int Size {
            get { return _items.Length; }
        }
        public T GetValue(int i) {
            return _items[i];
        }
        public void SetValue(int i, T val){
            _items[i] = val;
        }
        public void SetAll(T val) {
            for (var i = 0; i < _items.Length; i++) {
                _items[i] = val;
            }
        }
        public void Print() {
            for (var i = 0; i < _items.Length; i++) {
                Console.WriteLine(_items[i]);
            }
        }
        public static Vector<T> operator +(Vector<T> a, Vector<T> b)
        {
            var retVal = new Vector<T>(a.Size);
            for (var i = 0; i < retVal.Size; i++) {
                retVal.SetValue(i, a.GetValue(i) + b.GetValue(i));
            }
            return retVal;
        }
    }
}

Program.cs:

using Test;


var x = new Vector<Double>(3);
x.SetAll(3);
var y = new Vector<Double>(3);
y.SetAll(2);
var z = x + y;
z.Print();

在每个最小工作示例中,创建了两个长度为3的Double类型向量x和y,使得x的所有条目都为3,y的所有条目都为2。然后将这些向量相加,并将结果保存在向量z中。

C#项目编译没有错误,并产生以下输出
>
> 5
> 5
> 5
>
而VB.NET项目无法编译,并抛出上述错误。<br>
<br>
我甚至不太明白为什么首先会出现这个错误。类型参数被给予了实现接口INumber(Of T)的约束,该接口又实现了IAdditionOperators(Of T,T,T)接口,该接口公开了+-运算符。因此,我认为T应该能够依赖于该运算符,就像C#中那样,但在VB.NET中不行。<br>
<br>
这是我的错误还是VB.NET在这方面工作不正确?

英文:

First up, I am currently working with VB.NET and therefore not really knowledgeable in C#.

I wanted to create a custom generic Vector class with the constrain, that the type parameter must implement the interface INumber(Of T). However, when I tried to declare a +-operator in said class (using an element-wise addition of values given by two vectors), my VB.NET project produced following error:

>
> Error BC30452 Operator '+' is not defined for types 'T' and 'T'
>
Since I pretty much only tested the example given on this page and didn't really believe, that Microsoft would publish something that wouldn't work, I decided to also test my problem in C# (also using .NET 7).

For that I build following two MWEs in VB.NET

Vector.vb:

Imports System.Numerics


Public Class Vector(Of T As INumber(Of T))

    Private _items() As T

    Public Sub New(n As Integer)
        ReDim _items(n - 1)
    End Sub

    Public ReadOnly Property Size As Integer
        Get
            Return _items.Length
        End Get
    End Property

    Public Function GetValue(i As Integer) As T
        Return _items(i)
    End Function

    Public Sub SetValue(i As Integer, val As T)
        _items(i) = val
    End Sub

    Public Sub SetAll(val As T)
        For i As Integer = 0 To _items.Length - 1
            _items(i) = val
        Next
    End Sub

    Public Sub Print()
        For i As Integer = 0 To _items.Length - 1
            Console.WriteLine(_items(i))
        Next
    End Sub

    Public Shared Operator +(a As Vector(Of T), b As Vector(Of T)) As Vector(Of T)
        Dim retVal As New Vector(Of T)(a.Size)
        For i As Integer = 0 To retVal.Size - 1
            retVal.SetValue(i, a.GetValue(i) + b.GetValue(i))
        Next
        Return retVal
    End Operator

End Class

Program.vb:

Module Program
    Sub Main(args As String())
        Dim x As New Vector(Of Double)(3)
        x.SetAll(3)
        Dim y As New Vector(Of Double)(3)
        y.SetAll(2)
        Dim z = x + y
        z.Print()
    End Sub
End Module

<br>
<br>

and in C#

Vector.cs:

using System.Numerics;


namespace Test
{
    public class Vector&lt;T&gt; where T : INumber&lt;T&gt;
    {
        private T[] _items;

        public Vector(int n) {
            Array.Resize&lt;T&gt;(ref _items, n);
        }
        public int Size {
            get { return _items.Length; }
        }
        public T GetValue(int i) {
            return _items[i];
        }
        public void SetValue(int i, T val){
            _items[i] = val;
        }
        public void SetAll(T val) {
            for (var i = 0; i &lt; _items.Length; i++) {
                _items[i] = val;
            }
        }
        public void Print() {
            for (var i = 0; i &lt; _items.Length; i++) {
                Console.WriteLine(_items[i]);
            }
        }
        public static Vector&lt;T&gt; operator +(Vector&lt;T&gt; a, Vector&lt;T&gt; b)
        {
            var retVal = new Vector&lt;T&gt;(a.Size);
            for (var i = 0; i &lt; retVal.Size; i++) {
                retVal.SetValue(i, a.GetValue(i) + b.GetValue(i));
            }
            return retVal;
        }
    }
}

Program.cs:

using Test;


var x = new Vector&lt;Double&gt;(3);
x.SetAll(3);
var y = new Vector&lt;Double&gt;(3);
y.SetAll(2);
var z = x + y;
z.Print();

In each mwe two vectors (of Double) x,y with a length of 3 are created, so that all entries of x are 3 and all entries of y are 2. These vectors are then added together and saved in the vector z.

The C# project compiles without an error and produces follwing output
>
> 5
> 5
> 5
>
while the VB.NET project won't compile and throws above mentioned error.<br>
<br>
I don't even really understand why the error is thrown in the first place. The type parameter was given the constrain, that it has to implement the interface INumber(Of T), which in return implements the IAdditionOperators(Of T,T,T) interface, which in return exposes the +-operator. I therefore thought, that T should be able to rely on said operator, like it does in C#, but not in VB.NET.<br>
<br>
Is that an error on my site or is VB.NET not working correctly in that regard?

答案1

得分: 8

通用数学在C# 11中引入,该版本于2022年11月发布。

Visual Basic自2019年以来没有新版本。目前,微软对Visual Basic的声明策略是不采用需要对语言进行更改的功能:

我们将确保Visual Basic保持简单易用的语言,具有稳定的设计。.NET的核心库(如BCL)将支持VB,并且.NET运行时和库的许多改进将自动惠及VB。当C#或.NET运行时引入需要语言支持的新功能时,VB通常会采用仅限使用的方法,并避免使用新的语法。我们不计划将Visual Basic扩展到新的工作负载。

所以这只是C#获得了而Visual Basic没有的一个功能。随着时间的推移,将会有更多这样的功能,因为C#不断发展,而Visual Basic保持“稳定”。

英文:

Generic math was introduced in C# 11, which was released in November 2022.

Visual Basic hasn't had a new version since 2019. Currently, Microsoft's stated strategy for Visual Basic is to not adopt features that would require changes to the language:

> We will ensure Visual Basic remains a straightforward and approachable language with a stable design. The core libraries of .NET (such as the BCL) will support VB and many of the improvements to the .NET Runtime and libraries will automatically benefit VB. When C# or the .NET Runtime introduce new features that would require language support, VB will generally adopt a consumption-only approach and avoid new syntax. We do not plan to extend Visual Basic to new workloads.

So this is just a case of a feature that C# got that Visual Basic didn't. Over time, there will be more such features, as C# continues to evolve and Visual Basic stays "stable."

huangapple
  • 本文由 发表于 2023年8月9日 05:28:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/76863310.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定