Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a generic numeric type in C#?

Tags:

c#

.net

I'd really like a a generic numeric type as the second generic type parameter of the Func<TInput, THere, TResult> given below so I can provide either an integer or a double or a decimal as and when I like.

var _resultSelectors = new Dictionary<string, Func<DateTime, /*here*/ double, DateTime>>();

// so I can do
_resultSelector.Add("foo", (DateTime dt, int x) => ...);
_resultSelector.Add("bar", (DateTime dt, double d) => ...);
_resultSelector.Add("gar", (DateTime dt, float f) => ...);
_resultSelector.Add("har", (DateTime dt, decimal d) => ...);

Short of:

  1. making my own type; or
  2. using object and boxing a value type and unboxing it; or
  3. Using the dynamic keyword,

Is there a proper way to do that in C#?

I guess Java has a Number class that probably fits in my requirements but I was wondering if C# has anything similar.

I guess there isn't any such thing in C# but I thought I'll ask to be sure.

like image 764
Water Cooler v2 Avatar asked Jun 29 '16 12:06

Water Cooler v2


3 Answers

No, there is not. Generics and arithmetic operations (+, -, *, /, etc.) simply do not work together. This is an issue that is brought up many times and the C# design comitee has never addressed (to be fair, this feature would need work on the CLR too, as pointed out by Eric Lippert in answer linked further on).

Curisously, if you inspect the source code of the .NET Framework you'll see that in some stage of development there was an IArithmetic<T> interface, but it was scrapped; see here.

You can read more about it, in this SO answer.

like image 65
InBetween Avatar answered Oct 15 '22 22:10

InBetween


Even if there were a base type or interface that encompasses numeric types, because you've wrapped the constraint in a Func it wouldn't do you any good. the input types for Func are contravariant, so its parameters can't me more derived than what's declared.

In other words, you can't replace a Func<DateTime, ValueType, DateTime> with a Func<DateTime, int, DateTime> like you can with IEnumerable<T> (you can replace an IEnumerable<ValueType> with an IEnumerable<int>)

I think your best bets are dynamic (still type safe, but at run-time versus compile-time) or double or decimal if you want to do math and don't have to stay in the same type.

like image 44
D Stanley Avatar answered Oct 16 '22 00:10

D Stanley


C# 10 and .NET 6: Solution from November 2021 onwards

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

When you want any number, you could use INumber<T>. In case you need any specific operator, use the corresponding interfaces e.g. IAdditionOperators for a + b or IIncrementOperators for a++ etc.

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>
like image 1
SommerEngineering Avatar answered Oct 15 '22 23:10

SommerEngineering