-
Notifications
You must be signed in to change notification settings - Fork 5.4k
Description
Background and motivation
API proposal with motivation as a new take (with rationale) on #36264.
Currently, the following code fails because BigInteger does not implement IConvertible, even though its value is easily convertible to int (each line in example below ran in dotnet repl):
using System.Numerics;
var bi = new BigInteger(123);
Convert.ToInt32(bi) // fails
var t = typeof(int);
Convert.ChangeType(bi, t) // also failsThe error message of the first failure is:
System.InvalidCastException: Unable to cast object of type 'System.Numerics.BigInteger' to type 'System.IConvertible'.
In order to make runtime conversion to other integer (or even non-integer) values possible, BigInteger should implement IConvertible.
Rationale and use case: I have created a Lisp-based (and Scheme-based) interpreted/dynamic language on .NET called Lillisp. To implement Scheme's rational number types (i.e. 1/3), I am using the Rationals library, which implements the numerator and denominator as BigIntegers. This is useful for rational/integer division, such as (/ 3 4 5) which yields 3/20, where 3 and 20 are BigIntegers. Implementing the Scheme numerator and denominator functions is therefore trivial, they just return the BigInteger .Numerator and .Denominator properties of the Rational instance respectively. The problem is that the result of this call cannot be passed as-is to a method taking an int, for example. Lillisp has a cast function (aside: this should probably be renamed to convert or something) that takes a value and a runtime type and calls Convert.ChangeType, and I expected (cast (numerator (/ 3 4 5)) Int32) to yield the Int32 value 3, but instead it fails because BigInteger is not IConvertible. While I can add methods to explicitly convert a BigInteger to other types, or implement dynamic casting via IL Emit, it would be nice to be able to do the runtime conversion in the same way that other integer types can be done. The BigInteger type already has explicit cast operators for most if not all of the IConvertible destination types, so this would be a natural fit to make BigInteger act like other integer types. This sounds similar to the Powershell language concerns of using BigInteger in #36264.
API Proposal
namespace System.Numerics
{
// some attributes...
public readonly struct BigInteger : ISpanFormattable, IComparable, IComparable<BigInteger>, IEquatable<BigInteger>, IConvertible
{
// ... implement IConvertible members
}
}The IConvertible members could possibly just delegate to the explicit cast operators that already exist on BigInteger.
API Usage
var bi = new BigInteger(123);
var i = Convert.ToInt32(bi);
// or
var ci = Convert.ChangeType(bi, typeof(int));Alternative Designs
Unsure of what alternatives there could be to this change.
Risks
Adding an interface to BigInteger could be considered a breaking change.