Reputation: 128317
Suppose I want to write a function like the following (as usual, a trivial example for illustrative purposes):
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
As you can probably guess, this function causes an error because a generic object is not guaranteed to implement the + operator. As far as I know, though, any numerical type (Integer, Double, Decimal, etc.) will.
Is there a way to write a (quasi-)generic function that can accept any numerical type, without having to explicitly overload the function for every such type yourself?
Alternatively, I suppose an equally acceptable solution would be to somehow check if a type implements the '+' operator (or any operator generally associated with numerical types and used by the function).
Upvotes: 3
Views: 1157
Reputation: 1700
Great news: there is now a solution for this in .NET 6 and C# 10, cf. https://devblogs.microsoft.com/dotnet/preview-features-in-net-6-generic-math/#generic-math
I cannot estimate at the moment if this function will be available in VB.NET as well.
In order to accept any numerical type, use the INumber<T>
interface, e.g.:
public T Adding<T>(T a, T b)
where T : INumber<T>
where T : IAdditionOperators<T, T, T>
{
return a + b;
}
Note: At the time of my answer, this feature was only a preview. Microsoft will keep this for the final version of .NET 6 as they still want to allow breaking chances. To use the feature, preview features must be enabled in the project configuration:
<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>
Upvotes: 0
Reputation: 4007
You could use overloading instead. Either write an essentially identical function of each numeric type you want to support:
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
Or, if it has a lot of code in it, make your generic function private and wrap it with overload public functions:
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
It's not quite what you're after, but the public functions will be type safe.
Upvotes: 1
Reputation: 129
You can use lambda expressions, like this:
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);
}
It will not be typesafe, but it will work for types that has the expected operator (addition, in the example above).
Upvotes: 1
Reputation: 10839
Sorry you can't unless you create your own number class.
public static T Add<T> (T x, T y) where T: MyNumberClass
{
// your add code
...
}
The reason is that .NET only lets you constrain a generic method with a class or an interface.
Upvotes: 1
Reputation: 422026
No, since there's no specific common interface that all of them implement. In essence, there's no real notion of "numerical types" in the framework. Unless you wrap them in self-defined classes and have your method accept only your types (which is not really a direct answer to your question, just a workaround).
Upvotes: 8