3

So I have a class which looks something like this:

public class Foo<TKey>
{
   // ...
}

I have a method which uses the generic argument TKey as follows:

public int Test(TKey val)
{
   return val | 5;
}

I need to set constraints which ensure that TKey is a numeric value in order to use bitwise operators. Anyhow, you can not set constraints to ensure that it is a numeric value since short, int, double, ... do not implement an interface like INumeric.

Now the question is, would this be possible with only constraints?

thatguy
  • 21,059
  • 6
  • 30
  • 40
Twenty
  • 5,234
  • 4
  • 32
  • 67
  • 6
    There is only very few numeric types. And more importantly, the list is constant. So generics are not the right tool anyway. Just provide 1 function for the highest Int and float type you will need. – Christopher Dec 17 '19 at 10:06
  • https://stackoverflow.com/questions/3329576/generic-constraint-to-match-numeric-types take a look – svoychik Dec 17 '19 at 10:08
  • @Christopher Well sounds about right, will do that. You might want to post an answer which I can accept, so others will find the "solution" faster. – Twenty Dec 17 '19 at 10:19
  • Bitwise operators are defined for the `int`, `uint`, `long`, and `ulong` types. For other integral types (`sbyte`, `byte`, `short`, `ushort`, or `char`), their values are converted to the `int` – Pavel Anikhouski Dec 17 '19 at 11:00
  • Does this answer your question? [Generic constraint to match numeric types](https://stackoverflow.com/questions/3329576/generic-constraint-to-match-numeric-types) – Pavel Anikhouski Dec 17 '19 at 11:01
  • Well only kind of, I really like the solution that @Christopher provided. So I do not really want to use the answers provided in that post. – Twenty Dec 17 '19 at 11:10
  • Does `return (dynamic)val | 5` work? – g t Dec 17 '19 at 12:25
  • Well yes it would, but the constraint would still be missing. – Twenty Dec 17 '19 at 12:31

3 Answers3

2

In .NET 7 interfaces for generic maths were introduced that are implemented by numeric types. There is also a special interface for bitwise operations IBitwiseOperators<TSelf,TOther,TResult> that you can use. Of course, you can adapt the TOther and TResult arguments, depending on your requirements here. For simplicity, all arguments are of type TKey in this example (see the note below).

public TKey Test<TKey>(TKey val) where TKey : IBitwiseOperators<TKey, TKey, TKey>
{
   return val | 5;
}

The generalized inteface is INumber<T> that represents any numeric type. There are also more specialized numeric categories for binary or floating point numbers, see Numeric interfaces.

Note: The way you defined your method to perform a bitwise operation with any incoming numeric type instance and return an int will not work in general. E.g. if you pass a long and OR it with 5, it is still a long, which cannot be assigned directly to an int, which is smaller.

thatguy
  • 21,059
  • 6
  • 30
  • 40
1

Generics are about allowing any Random class that any Programmer on the planet might throw in for T. However the numeric types are actually a very static list. I would never expect a programmer to make his own numeric type. Stuff with a overloaded Operators including binary ones? Maybe rarely.

So this is very much not a generic case. If you only write code for 2 - maybe 3 - types you should cover just about every generic in existence:

  • the highest range integer you have to expect signed Int64 IIRC
  • the highest range floating point you have to expect. IIRC, Decimal*.
  • optionally BigInteger, for when you have to expect really big numbers. However a short look revealed that none of Math class functions support BigInt values. They keep it to Decimal, Double and many smaler built in Numerics. So this case might have been dropped as to rare and to easy to get wrong.

*Correction: While Decimal has the highest amount of digits of precision and bigest size at 64 bit, Double has the bigger range. By an order of Magnitude, that itself has an order of Magnitude.

Christopher
  • 9,634
  • 2
  • 17
  • 31
0

Try this code:

    public static int Test<TKey>(TKey val) where TKey : struct, IComparable
    {
        int numberValue = Convert.ToInt32(val);
        return numberValue | 5;
    }

This is should work!

mikenlanggio
  • 1,122
  • 1
  • 7
  • 27
  • 1
    Well yea, but that would make a lot of the stuff useless, I really don't want to always convert it to `Int32`. Anyhow I will do some testing with it. – Twenty Dec 17 '19 at 10:17
  • @Twenty "I really don't want to always convert it to Int32" - in that case you should say so in your question! I assume you would want to convert the return type to "TKey"? – Matthew Watson Dec 17 '19 at 10:17
  • @Twenty It's impossible! – mikenlanggio Dec 17 '19 at 10:19
  • Well yea I noticed that, I'll do what @Christopher suggested. Thanks anyway :) – Twenty Dec 17 '19 at 10:19