Water Cooler v2
Water Cooler v2

Reputation: 33850

Is there a generic numeric type in C#?

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.

Upvotes: 13

Views: 3787

Answers (3)

SommerEngineering
SommerEngineering

Reputation: 1700

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>

Upvotes: 5

D Stanley
D Stanley

Reputation: 152566

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.

Upvotes: 5

InBetween
InBetween

Reputation: 32760

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.

Upvotes: 13

Related Questions