Chciałbym sprawdzić, czy obiekt jest tak wiele, że .ToString()
spowodowałoby ciąg zawierający cyfry i +
, -
,.
Czy jest to możliwe przez proste sprawdzanie typów w .net (np.:) if (p is Number)
?
Czy powinienem przekonwertować na ciąg, a następnie spróbować przeanalizować podwojenie?
Aktualizacja: Aby wyjaśnić, że mój obiekt to int, uint, float, double i tak dalej, nie jest to ciąg. Próbuję utworzyć funkcję, która serializuje dowolny obiekt do XML w następujący sposób:
<string>content</string>
lub
<numeric>123.3</numeric>
lub zgłoś wyjątek.
c#
.net
serialization
xml-serialization
Piotr Czapla
źródło
źródło
Odpowiedzi:
Będziesz musiał po prostu sprawdzić typ dla każdego z podstawowych typów liczbowych.
Oto metoda rozszerzenia, która powinna wykonać zadanie:
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; }
Powinno to obejmować wszystkie typy liczbowe.
Aktualizacja
Wygląda na to, że faktycznie chcesz przeanalizować liczbę z ciągu podczas deserializacji. W takim przypadku prawdopodobnie najlepiej byłoby użyć
double.TryParse
.string value = "123.3"; double num; if (!double.TryParse(value, out num)) throw new InvalidOperationException("Value is not a number.");
Oczywiście nie obsługiwałoby to bardzo dużych liczb całkowitych / długich miejsc po przecinku, ale w takim przypadku wystarczy dodać dodatkowe wywołania do
long.TryParse
/decimal.TryParse
/ cokolwiek innego.źródło
Zaczerpnięte z bloga Scotta Hanselmana :
public static bool IsNumeric(object expression) { if (expression == null) return false; double number; return Double.TryParse( Convert.ToString( expression , CultureInfo.InvariantCulture) , System.Globalization.NumberStyles.Any , NumberFormatInfo.InvariantInfo , out number); }
źródło
double.Parse(double.MaxValue.ToString())
powodujeOverflowException
. Możesz temu zaradzić, podając.ToString("R")
w tym przypadku modyfikator przesyłania w obie strony , ale to przeciążenie nie jest dostępne,Convert.ToString(...)
ponieważ nie znamy typu. Wiem, że to trochę marginalna sprawa, ale natknąłem się na to podczas pisania testów dla mojego własnego.IsNumeric()
rozszerzenia. Moim "rozwiązaniem" było dodanie przełącznika sprawdzania typu przed próbą przeanalizowania czegokolwiek. Zobacz moją odpowiedź na to pytanie dla kodu.Skorzystaj z właściwości IsPrimitive, aby utworzyć przydatną metodę rozszerzenia:
public static bool IsNumber(this object obj) { if (Equals(obj, null)) { return false; } Type objType = obj.GetType(); objType = Nullable.GetUnderlyingType(objType) ?? objType; if (objType.IsPrimitive) { return objType != typeof(bool) && objType != typeof(char) && objType != typeof(IntPtr) && objType != typeof(UIntPtr); } return objType == typeof(decimal); }
EDYCJA: Naprawiono zgodnie z komentarzami. Typy ogólne zostały usunięte od czasu, gdy pola .GetType () mają typy wartości. Uwzględniono również poprawkę dla wartości dopuszczających wartość null.
źródło
object
istring
nie są typami prymitywnymi.Powyżej znajduje się kilka świetnych odpowiedzi. Oto rozwiązanie typu „wszystko w jednym”. Trzy przeciążenia w różnych okolicznościach.
// Extension method, call for any object, eg "if (x.IsNumeric())..." public static bool IsNumeric(this object x) { return (x==null ? false : IsNumeric(x.GetType())); } // Method where you know the type of the object public static bool IsNumeric(Type type) { return IsNumeric(type, Type.GetTypeCode(type)); } // Method where you know the type and the type code of the object public static bool IsNumeric(Type type, TypeCode typeCode) { return (typeCode == TypeCode.Decimal || (type.IsPrimitive && typeCode != TypeCode.Object && typeCode != TypeCode.Boolean && typeCode != TypeCode.Char)); }
źródło
Zamiast przesuwać własny, najpewniejszym sposobem
Microsoft.VisualBasic
sprawdzenia, czy typ wbudowany jest numeryczny, jest prawdopodobnie odwołanie się i wywołanieInformation.IsNumeric(object value)
. Implementacja obsługuje wiele subtelnych przypadków, takich jakchar[]
ciągi HEX i OCT.źródło
Istnieją trzy różne koncepcje:
is
- na przykładif(obj is int) {...}
TryParse()
ToString()
może dać coś, co wygląda jak liczba, wywołajToString()
i potraktuj to jako ciągW obu pierwszych dwóch przypadkach prawdopodobnie będziesz musiał osobno obsłużyć każdy typ liczbowy, który chcesz obsługiwać (
double
/decimal
/int
) - na przykład każdy ma inny zakres i dokładność.Możesz również spojrzeć na wyrażenie regularne, aby szybko sprawdzić przybliżone.
źródło
Zakładając, że dane wejściowe to ciąg ...
Istnieją 2 sposoby:
użyj Double.TryParse ()
double temp; bool isNumber = Double.TryParse(input, out temp);
użyj Regex
bool isNumber = Regex.IsMatch(input,@"-?\d+(\.\d+)?");
źródło
Możesz użyć takiego kodu:
if (n is IConvertible) return ((IConvertible) n).ToDouble(CultureInfo.CurrentCulture); else // Cannot be converted.
Jeśli przedmiot jest
Int32
,Single
,Double
itd. Będzie wykonywać konwersję. Ponadto łańcuch implementuje,IConvertible
ale jeśli ciąg nie jest konwertowany na podwójny,FormatException
zostanie wyrzucony a.źródło
Jeśli twoje wymaganie jest naprawdę
i chcesz użyć double.TryParse, musisz użyć przeciążenia, które przyjmuje parametr NumberStyles, i upewnij się, że używasz niezmiennej kultury.
Na przykład dla liczby, która może mieć wiodący znak, bez wiodących lub końcowych białych znaków, bez separatora tysięcy i separatora dziesiętnego kropki, użyj:
NumberStyles style = NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint | double.TryParse(input, style, CultureInfo.InvariantCulture, out result);
źródło
Pisząc własną
object.IsNumeric()
metodę rozszerzenia opartą na odpowiedzi Saula Dolgina na to pytanie, natknąłem się na potencjalny problem polegający na tym, że otrzymasz,OverflowException
jeśli spróbujesz zdouble.MaxValue
lubdouble.MinValue
.Moim „rozwiązaniem” było połączenie zaakceptowanej odpowiedzi od Noldorina z odpowiedzią od Saula Dolgina i dodanie przełącznika dopasowania wzorca przed próbą przeanalizowania czegokolwiek (i skorzystanie z dobroci C # 7, aby trochę uporządkować):
public static bool IsNumeric(this object obj) { if (obj == null) return false; switch (obj) { case sbyte _: return true; case byte _: return true; case short _: return true; case ushort _: return true; case int _: return true; case uint _: return true; case long _: return true; case ulong _: return true; case float _: return true; case double _: return true; case decimal _: return true; } string s = Convert.ToString(obj, CultureInfo.InvariantCulture); return double.TryParse(s, NumberStyles.Any, NumberFormatInfo.InvariantInfo, out double _); }
źródło
Tak, to działa:
object x = 1; Assert.That(x is int);
W przypadku liczby zmiennoprzecinkowej musiałbyś przetestować przy użyciu typu zmiennoprzecinkowego:
object x = 1f; Assert.That(x is float);
źródło