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:
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.
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.
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.
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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With