Is there a C# equivalent to Java's Number class? - c#

I'm new to C#, coming from Java, and I'd like to check whether a certain object is a Number (it can be an Integer, Double, Float, etc). In Java I did this by saying if (toRet instanceof Number). I'm hoping there's a similar C# thing like if (toRet is Number) but thus far I haven't been able to find a Number class that does this. Is there a way to do this, or do I have to manually check for Integer, Double, etc?
Edit for more info: Basically what I want to do is eventually have a byte array. However, when the array is stored in a text file, the parser I'm using can sometimes think it's an integer array or a double array. In Java, I had this:
JSONArray dblist = (JSONArray)result_;
byte[] reallyToRet = new byte[dblist.size()];
Object toComp = dblist.get(0);
if (toComp instanceof Number)
for (int i=0; i < dblist.size(); ++i) {
byte elem = ((Number) dblist.get(i)).byteValue();
reallyToRet[i] = elem;
}
return reallyToRet;
}
The important bit here is the if statement. Sometimes the objects in dblist would parse as integers, sometimes as doubles, and only rarely as bytes, but all I really care about at the end is the byte value.

Well, yeah, but it's an extension method that just ORs all the possibilities.
This is it:
public static bool IsNumber(this object value)
{
return value is sbyte
|| value is byte
|| value is short
|| value is ushort
|| value is int
|| value is uint
|| value is long
|| value is ulong
|| value is float
|| value is double
|| value is decimal
|| value is BigInteger;
}
and you would use it like this:
if (toRet.IsNumber());
This needs to be in a static class.

I am not sure about any class for that. But you can check for instance, for integer see
int val;
if(Int32.TryParse(integer, out val))
else
Unlikely, you can use Double.TryParse(number, out val) etc.

Related

Convert string to INT in C# (When String is 'E0305' To convert INT is not Work

I want to convert string to int but some time is not working.
Here is my code:
public static int ToInt(String pStr)
{
return Convert.ToInt32(Microsoft.VisualBasic.Conversion.Val(pStr));
}
Int i = ToInt("F0005");
Output is 0 - it works fine.
But when I pass in a value like this
Int i = ToInt("E0305");
Then I get an error "Out-of-range exception".
I have a mix of values, some are int and some are strings; I want to pass each and every value in loop and convert it to int, but when I pass this value then I get an error.
If you just want to skip invalid string value, it is better to use TryParse instead of returning 0 (which might be valid value). At your calling code it should look like this:
string val = "F0005";
if (int.TryParse(val, out int i) {
// parse success. you can use i here
}
else {
// parse failed.
}
If you really want it to be 0, this should work
string val = "F0005";
int i = int.TryParse(val, out int x) ? x : 0;
You can do it in C# alone without VB.NET library
public static int ToInt(string pStr)
{
return int.Parse(pstr);
}
Noted that this will throw exception if pStr is not a valid integer string. In your case, it might also throw exception if the value is too big, which you might need long instead to hold bigger numbers.
public static long ToInt64(string pStr)
{
return long.Parse(pstr);
}
Also, I just noticed that you are trying to parse "E0305" which is not really a valid format (as far as I know). The closest one is "1E305", which means 1 with 305 zeroes afterward. If you need to parse an integer that big, you might need BigInteger
public static BigInteger ToBigInteger(string pStr)
{
return BigInteger.Parse(pstr, System.Globalization.NumberStyles.AllowExponent);
}
The System.Globalization.NumberStyles.AllowExponent part is there to allow parsing the number in exponent representation.
Try using int.TryParse() method for those cases where you have some unexpected and you do not want exceptions in proces of parsing them.
Use case for it would be:
var isValid = int.TryParse(pStr, out int result);
Also another benefit of using it is that you have return value that provides you a way to handle unsuccessful parsing call.

Unchecked assignment in generic function

I'm trying to write a generic method to perform an unchecked assignment from a long to other type. Here is the simplified version:
private static void AssignHex<T>(string hex, out T val) where T : struct
{
if (long.TryParse(hex, NumberStyles.AllowHexSpecifier, null, out long lval))
{
unchecked
{
val = (T)Convert.ChangeType(lval, typeof(T));
}
}
else
{
val = default(T);
}
}
This works fine except for input string "FFFFFFFF" and type int where I expect to get -1 and instead get overflow exception. The equivalent non-generic method works fine:
private static void AssignHex2(string hex, out int val)
{
if (long.TryParse(hex, NumberStyles.AllowHexSpecifier, null, out long lval))
{
unchecked
{
val = (int)lval;
}
}
else
{
val = default(int);
}
}
I can simply write non-generics but it bothers me that I can't get the generic version to work. Any solution?
While System.Convert.ChangeType is really handy a lot of times but you cannot use it in your scenario. FFFFFFFF in decimal is ‭4294967295 which cannot be represented in int type and conversion fails. Specific code that throws is this (there is a check if long is larger than maximal int value).
If you want this functionality, then you will have to manually write similar code as is in System.Convert.ChangeType - if statements on different possible types with appropriate casts wrapped in unchecked block. Or simply not use generics and have overload for each type that you are interested in.
EDIT: It may be better to remove unchecked blocks altogether and parse hex value directly to appropriate type instead of parsing it first to long. This way you will directly parse it to expected value and receive error if value is out of range instead of just silently ignoring leftover bits with unchecked block.
EDIT2: Negative numbers are represented using two's complement. In short you can get negative number from positive by flipping all bits which represent positive number and adding 1. This means that binary or hex representation of negative number depends on how many bits are allocated for a number. So for 8 bit number (sbyte) -1 is 0xFF, for 16 bit number (short) is 0xFFFF, for 32 bit number (int) is 0xFFFFFFFF and for 64 bit number (long) is 0xFFFFFFFFFFFFFFFF. Since you are parsing hex value 0xFFFFFFFF as long this is not -1, since you are actually parsing 0x0000000FFFFFFFF. What your unchecked block does is that when casting to lower precision number it will just take as many bits as required for lower precision type and discard the rest without any checks. Imagine now that you have 0XF0000000FFFFFFFF. If you parse this as long you get ~ -1 quintillion but with unchecked cast to int you would get -1, totally ignoring the most significant 4 bits.
Ok. Some pain was involved, but here is the answer:
private static bool AssignHex4<T>(string hex, out T val)
{
Type t = typeof(T);
MethodInfo mi = t.GetMethod("TryParse", new Type[] { typeof(string), typeof(NumberStyles), typeof(IFormatProvider), typeof(T).MakeByRefType()});
if (mi != null)
{
object[] parameters = new object[] {hex, NumberStyles.AllowHexSpecifier, null, null};
object result = mi.Invoke(null, parameters);
if ((bool) result)
{
val = (T)parameters[3];
return true;
}
}
val = default(T);
return false;
}
Shout outs are required to a few SO answers that were instrumental in putting this together:
MethodInfo.Invoke with out Parameter
Specifying out params for Type.GetMethod
I'll admit it is not a particularly elegant answer, but I think it is comprehensive and that is what I was looking for.
Consider...
AssignHex4("FF", out byte r1);
AssignHex4("FFFF", out short r2);
AssignHex4("FFFFFFFF", out int r3);
AssignHex4("FFFFFFFFFFFFFFFF", out long r4);
AssignHex4("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", out BigInteger r5);
Console.WriteLine("Convert in reflection function returns:" + r1 + ", " + r2 + ", " + r3 + ", " + r4 + ", " + r5);
results in...
Convert in reflection function returns:255, -1, -1, -1, -1

Why do the SByte and Int32 CompareTo() methods behave differently?

If you run the following code:
SByte w = -5;
Console.WriteLine(w.CompareTo(0));
Int32 x = -5;
Console.WriteLine(x.CompareTo(0));
SByte y = 5;
Console.WriteLine(y.CompareTo(0));
Int32 z = 5;
Console.WriteLine(z.CompareTo(0));
then you get the following output:
-5
-1
5
1
Why do these methods with the same name that have almost identical descriptions in the MSDN documentation behave so differently?
Because the SByte.CompareTo() is implemented like
return m_value - value;
so a simple subtraction. This works because the m_value is converted automatically to int, and any possibile combination of values is "legal" with int.
With two Int32 this can't be done, because for example Int32.MinValue.CompareTo(Int32.MaxValue) would become Int32.MinValue - Int32.MaxValue that would be outside the int range, and in fact it is implemented as two comparisons:
if (m_value < value) return -1;
if (m_value > value) return 1;
return 0;
in general
The only important "thing" of the returned value of a CompareTo is its sign (or if it is 0). The "value" is irrelevant. The return value of 1, 5, 500, 5000, 5000000 of CompareTo() are the same. CompareTo can't be used to measure "distance" between numbers. So both implementations are equivalent.
It is totally wrong to do:
if (someValue.CompareTo(someOtherValue) == -1)
you must always
if (someValue.CompareTo(someOtherValue) < 0)
why the SByte.CompareTo is built that way
SByte.CompareTo is implementing a "branchless" comparison (there are no ifs in the code, the flow of code is linear). Processors have problems with branches, so branchless code could be faster than "branchful" code, so this microoptimization. Clearly SByte.CompareTo could have been written as Int32.CompareTo.
why any negative value is equivalent to -1 (and any positive value is equivalent to +1)
This is probably something that is derived directly from the C language: the qsort function for example to compare items uses a user-defined method that is like:
Pointer to a function that compares two elements.
This function is called repeatedly by qsort to compare two elements. It shall follow the following prototype:
int compar (const void* p1, const void* p2);
Taking two pointers as arguments (both converted to const void*). The function defines the order of the elements by returning (in a stable and transitive manner):
return value meaning
<0 The element pointed to by p1 goes before the element pointed to by p2
0 The element pointed to by p1 is equivalent to the element pointed to by p2
>0 The element pointed to by p1 goes after the element pointed to by p2
how is the .CompareTo implemented in other primitive types?
SByte, Byte, Int16, UInt16, Char all use the subtraction "method", while Int32, UInt32, Int64, UInt64 all use the if "method".
Looking at the source for these two methods, they are implemented differently:
public int CompareTo(sbyte value)
{
return (int)(this - value);
}
vs
public int CompareTo(int value)
{
if (this < value)
{
return -1;
}
if (this > value)
{
return 1;
}
return 0;
}
But none of this matters, since the sign of the returned value is the only thing that you should be checking.

C# Method Overloading

I have a method that needs to allow a wide variety of input types. There are two categories of arguments: boundary type arguments, and actual data input arguments.
The boundary arguments are for example, order, frequency, number of points, and number of data points. These boundary arguments are of type int and are common, regardless of the actual data input argument type.
The actual input arguments may be of types: byte, int, short, uint, float, double, decimal, long, etc. To complicate matters further, the actual input data may be individual data, or a list or array of that type. So, the actual input may come as List or uint[], etc. This input is ultimately converted to type double - either as single data or double[].
The method consists of three parts: part one checks the validity of the boundary arguments. This part always applies regardles of the actual input data type. Part two checks and processes the input data arguments. This part changes depending of the type of the input data. Part three performs calculations on the data and is once again common.
I have thought about generic, and I have thought about standard overloading with generics but both seem inefficient. I have come up with what I believe is a workable solution but would appreciate comments: Is my approach computationally efficent, and is there a better way to do this. Your comments would be appreciated.
This is what I currently have:
// ... create lists to store data
static List<double> aList = new List<double>(8);
static List<double> fList = new List<double>(8);
public static double[] MyMethod(int numPts, int numData, object aValue, object fValue)
{
// ... part 1
if (numData < 2) throw new ArgumentOutOfRangeException("numberData must be >= 2.");
if (numPts < 2) throw new ArgumentOutOfRangeException("numberPoints must be >= 2.");
if (numData < numPts) throw new ArgumentOutOfRangeException("numberData must be
>= numPts.");
// ... part 2
if (aValue is byte || aValue is short || aValue is int || aValue is long ||
aValue is float || aValue is double || aValue is decimal ||
aValue is List<byte> || aValue is byte[] || aValue is List<short> ||
aValue is short[] || aValue is List<int> || aValue is int[] ||
aValue is List<float> || aValue is float[] || aValue is List<double> ||
aValue is double[])
{ }
else throw new ArgumentException("a values must be of a numeric type.");
double a = 0.0;
if (aValue is byte || aValue is short || aValue is int || aValue is long ||
aValue is float || aValue is double || aValue is decimal)
{
a = (double)aValue;
// ... store individual values
aList.Add(a);
// ... create the x variable vector
double[] x = aList.ToArray(); // a values
}
else if (aValue is List<byte> || aValue is List<short> || aValue is List<int> ||
aValue is List<float> || aValue is List<double>)
{
// ... get the runtime type of the aValue object
Type t = aValue.GetType();
// ... convert the aValue object to a generic list
IList tmp = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(t));
// ... convert the generic list to a strongly typed list
List<double> aValuesList = tmp.Cast<double>().ToList();
// ... create the x variable vector
double[] x = aValuesList.ToArray(); // a values
}
else
{
// ... process the vector input
// ... get the runtime type of the aValue object
Type t = aValue.GetType();
// ... convert the aValue object to an array
Array tmp = Array.CreateInstance(typeof([]).MakeGenericType(t), aValue.Length);
// ... convert the generic array to a strongly typed array
double[] x = tmp.Cast<double>().ToArray();
}
// ... part 3
{
// ... do calculations
}
}
Just make it accept a double[]. Let the calling code massage their data into the correct format, or provide overloads for the other datatypes.
As an example, if your method is:
public double[] Calculate(double[] aValue, double[] fValue, ...)
{
}
You can provide overloads like:
public double[] Calculate(double aValue, double fValue, ...)
{
return Calculate(new double[]{aValue}, new double[]{fValue}, ...);
}
public double[] Calculate(IEnumerable<double> aValue, IEnumerable<double> fValue, ...)
{
return Calculate(aValue.ToArray(), fValue.ToArray(), ...);
}
To cover other datatypes you can reduce the number of overloads by using something like:
public double[] Calculate<T>(T aValue, T fValue) where T : IConvertible
{
return Calculate(aValue.ToDouble(), fValue.ToDouble(), ...);
}
public double[] Calculate<T>(IEnumerable<T> aValue, IEnumerable<T> fValue) where T : IConvertible
{
return Calculate(aValue.Select(x=>x.ToDouble()), fValue.Select(x=>x.ToDouble()), ...);
}
This should cover all other primitive data types, which is all of your example.
If you do this, the code in your calculate method is reduced down to:
public double[] Calculate(double[] aValue, double[] fValue, int numData, int numPts)
{
if (numData < 2) throw new ArgumentOutOfRangeException("numberData must be >= 2.");
if (numPts < 2) throw new ArgumentOutOfRangeException("numberPoints must be >= 2.");
if (numData < numPts) throw new ArgumentOutOfRangeException("numberData must be
>= numPts.");
// do calculation
}
... which is a lot simpler.
You really don't want to do that.
Since your input is quite complex, and with many checks, you should put all of it into a class that will take care of all the checks. The various types of inputs just beg to become derived classes.
I think a bunch of overloads would be the way to go. Each one would be fairly simple, just calling the main method. But then all of your data type testing is done by the compiler, rather than by your huge if statements. You could also set a flag in each overload to tell your main method if you received a single number, a List<> or an array (or whatever else you need to handle). For example:
enum DataType { SingleNumber, NumberList, NumberArray }
// one of many overloads
public static double[] MyMethod(int numPts, int numData, byte aValue, object fValue) {
return MyMethod(numPts, numData, (object)aValue, fValue, DataType.SingleNumber);
}
You have 2 stages there... First you're checking everything, and then aValue separately.
So, separate it.
Then you can use generics to call the specific function for the aValue type
void foo<T> (T aValue) where T : struct { } //value type
void foo<T> (List<T> aValue) where T : struct { } //List of value type
void foo<T> (T[] aValue) where T : struct { } //Array of value type
If you wan a better constraint for numeric types: Generic constraint to match numeric types
If you don't want to require the caller to convert its data to a double[] then by all means do it in the callee. But please delegate it to another function! It's much easier to read what's going on:
public static double[] MyMethod(int numPts, int numData, object aValue, object fValue)
{
//validation omitted for brevity
// ... part 2
double[] aValues = ToDoubleArray(aValue);
// ... the rest
}
Done!
Here's an implementation, though there's doubtless a more robust and/or efficient one:
private double[] ToDoubleArray(object aValue)
{
if (aValue is byte || aValue is short || aValue is int || aValue is long
|| aValue is float || aValue is double || aValue is decimal)
return new double[] { Convert.ToDouble(aValue) };
if (aValue is IEnumerable)
return ((IEnumerable)aValue).Select(Convert.ToDouble).ToArray();
throw new ArgumentException("The value was of an unsupported type", "aValue");
}
Done!

C#. How come when I use TextReader.Read() it returns an int value? Possible to convert to char?

So TextReader.ReadLine() returns a string, but TextReader.Read() returns an int value. This int value also seems to be in some sort of format that I don't recognize. Is it possible to convert this integer to a character? Thanks for any help.
EDIT:
TextReader Values = new StreamReader(#"txt");
string SValue1;
int Value1;
Value1 = Values.Read();
Console.WriteLine(Value1);
Console.ReadKey();
When it reads out the value it gives me 51 as the output. The first character in the txt file is 3. Why does it do that?
According to the documentation for the StringReader class (a sub-class of TextReader), the return value of Read() can be converted to a char, but you need to check if you're at the end of file/string first (by checking for -1). For example, in this modified code from the documentation:
while (true)
{
int integer = stringReader.Read();
// Check for the end of the string before converting to a character.
if (integer == -1)
break;
char character = (char) integer; // CONVERT TO CHAR HERE
// do stuff with character...
}
The documentation tells you: it returns -1 if there is no more data to read, and otherwise it returns the character, as an integer. The integer is not "in some sort of format"; integers are raw data. It is, rather, characters that are "formatted"; bytes on the disk must be interpreted as characters.
After checking for -1 (which is not a valid character value and represents the end of stream - that's why the method works this way: so you can check), you can convert by simply casting.
Read returns an int o that end-of-stream (-1) can be detected. Yes, you just cast the result to a char as in var c = (int) reader.Read();.
Typical usage:
while (true)
{
int x = reader.Read();
if (x == -1) break;
char c = (char) x;
// Handle the character
}

Categories

Resources