有没有办法确定给定的.Net类型是否为数字?例如:System.UInt32/UInt16/Double
都是数字.我想避免使用长开关盒Type.FullName
.
Phi*_*ace 98
试试这个:
Type type = object.GetType();
bool isNumber = (type.IsPrimitiveImple && type != typeof(bool) && type != typeof(char));
Run Code Online (Sandbox Code Playgroud)
基元类型是布尔,字节,SByte,Int16,UInt16,Int32,UInt32,Int64,UInt64,Char,Double和Single.
再采取Guillaume的解决方案:
public static bool IsNumericType(this object o)
{
switch (Type.GetTypeCode(o.GetType()))
{
case TypeCode.Byte:
case TypeCode.SByte:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
case TypeCode.Decimal:
case TypeCode.Double:
case TypeCode.Single:
return true;
default:
return false;
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
int i = 32;
i.IsNumericType(); // True
string s = "Hello World";
s.IsNumericType(); // False
Run Code Online (Sandbox Code Playgroud)
Jon*_*eet 86
不要使用开关 - 只需使用一套:
HashSet<Type> NumericTypes = new HashSet<Type>
{
typeof(decimal), typeof(byte), typeof(sbyte),
typeof(short), typeof(ushort), ...
};
Run Code Online (Sandbox Code Playgroud)
编辑:使用类型代码的一个优点是,当新的数字类型被引入.NET(例如BigInteger和Complex)时,它很容易调整 - 而这些类型将不会获得类型代码.
Jür*_*ock 65
没有任何解决方案考虑Nullable.
我修改了Jon Skeet的解决方案:
private static HashSet<Type> NumericTypes = new HashSet<Type>
{
typeof(int),
typeof(uint),
typeof(double),
typeof(decimal),
...
};
internal static bool IsNumericType(Type type)
{
return NumericTypes.Contains(type) ||
NumericTypes.Contains(Nullable.GetUnderlyingType(type));
}
Run Code Online (Sandbox Code Playgroud)
我知道我可以将nullables本身添加到我的HashSet中.但是这个解决方案避免了忘记在列表中添加特定Nullable的危险.
private static HashSet<Type> NumericTypes = new HashSet<Type>
{
typeof(int),
typeof(int?),
...
};
Run Code Online (Sandbox Code Playgroud)
Gui*_*ume 36
public static bool IsNumericType(Type type)
{
switch (Type.GetTypeCode(type))
{
case TypeCode.Byte:
case TypeCode.SByte:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
case TypeCode.Decimal:
case TypeCode.Double:
case TypeCode.Single:
return true;
default:
return false;
}
}
Run Code Online (Sandbox Code Playgroud)
关于优化的注意事项已删除(参见enzi注释)
如果你真的想要优化它(失去可读性和安全性......):
public static bool IsNumericType(Type type)
{
TypeCode typeCode = Type.GetTypeCode(type);
//The TypeCode of numerical types are between SByte (5) and Decimal (15).
return (int)typeCode >= 5 && (int)typeCode <= 15;
}
Run Code Online (Sandbox Code Playgroud)
arv*_*man 14
基本上是Skeet的解决方案,但您可以将其重用于Nullable类型,如下所示:
public static class TypeHelper
{
private static readonly HashSet<Type> NumericTypes = new HashSet<Type>
{
typeof(int), typeof(double), typeof(decimal),
typeof(long), typeof(short), typeof(sbyte),
typeof(byte), typeof(ulong), typeof(ushort),
typeof(uint), typeof(float)
};
public static bool IsNumeric(Type myType)
{
return NumericTypes.Contains(Nullable.GetUnderlyingType(myType) ?? myType);
}
}
Run Code Online (Sandbox Code Playgroud)
基于Philip的提议的方法,通过SFun28的内部类型检查增强了Nullable
类型:
public static class IsNumericType
{
public static bool IsNumeric(this Type type)
{
switch (Type.GetTypeCode(type))
{
case TypeCode.Byte:
case TypeCode.SByte:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
case TypeCode.Decimal:
case TypeCode.Double:
case TypeCode.Single:
return true;
case TypeCode.Object:
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
return Nullable.GetUnderlyingType(type).IsNumeric();
//return IsNumeric(Nullable.GetUnderlyingType(type));
}
return false;
default:
return false;
}
}
}
Run Code Online (Sandbox Code Playgroud)
为什么这个?我必须检查给定Type type
是否是数字类型,而不是任意object o
数字.
具有空类型支持的类型扩展。
public static bool IsNumeric(this Type type)
{
if (type == null) { return false; }
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
type = type.GetGenericArguments()[0];
}
switch (Type.GetTypeCode(type))
{
case TypeCode.Byte:
case TypeCode.SByte:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
case TypeCode.Decimal:
case TypeCode.Double:
case TypeCode.Single:
return true;
default:
return false;
}
}
Run Code Online (Sandbox Code Playgroud)
利用、 和修改了skeet和arviman 的解决方案。Generics
C# v7.0
编辑:很多个月后回来以提高代码质量。
using System;
using System.Collections.Generic;
using System.Numerics;
public static class GenericTypeExtensions
{
private static readonly HashSet<Type> _numericTypes = new HashSet<Type>
{
typeof(int), typeof(double), typeof(decimal),
typeof(long), typeof(short), typeof(sbyte),
typeof(byte), typeof(ulong), typeof(ushort),
typeof(uint), typeof(float), typeof(BigInteger)
};
public static bool IsNumeric<T>(this T input)
{
if (input is null) return false;
return _numericTypes.Contains(typeof(T));
}
public static bool IsNumericAtRuntime<T>(this T input)
{
if (input is null) return false;
return _numericTypes.Contains(input.GetType());
}
/// <summary>
/// Identifies whether or not this object is a numeric or nullable numeric type.
/// <para>Examples</para>
/// <para />int value = 0; true
/// <para />var objValue = (object)(int)0; true
/// <para />int? value = 0; true
/// <para />int? value = null; true
/// <para />var objValue = (object)(int?)0; true
/// <para />var objValue = (object)(int?)(null); false - because (int?) is totally lost.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="input"></param>
/// <returns></returns>
public static bool IsNullableNumeric<T>(this T input)
{
if (input is null)
{
return _numericTypes.Contains(Nullable.GetUnderlyingType(typeof(T))); // see what the inner base type is
}
return _numericTypes.Contains(input.GetType());
}
public static void AddCustomNumericType<T>(this T _) where T : IComparable, IComparable<T>, IConvertible, IEquatable<T>, IFormattable
{
_numericTypes.Add(typeof(T));
}
public static bool TryAddCustomNumeric<T>(T input)
{
Type type;
if (input is null)
{
type = Nullable.GetUnderlyingType(typeof(T));
if (type is null) return false;
}
else
{ type = input.GetType(); }
if (_numericTypes.Contains(type)) return true;
var interfaces = type.GetInterfaces();
var count = 0;
for (var i = 0; i < interfaces.Length; i++)
{
switch(interfaces[i])
{
case IComparable:
case IComparable<T>:
case IConvertible:
case IEquatable<T>:
case IFormattable:
count++;
break;
default: continue;
}
}
if (count != 5) return false;
_numericTypes.Add(type);
return true;
}
public static bool TryAddCustomNumericType<T>(Type type)
{
if (type is null) return false;
if (_numericTypes.Contains(type)) return true;
var interfaces = type.GetInterfaces();
var count = 0;
for (var i = 0; i < interfaces.Length; i++)
{
switch (interfaces[i])
{
case IComparable:
case IComparable<T>:
case IConvertible:
case IEquatable<T>:
case IFormattable:
count++;
break;
default: continue;
}
}
if (count != 5) return false;
_numericTypes.Add(type);
return true;
}
Run Code Online (Sandbox Code Playgroud)
示例/单元测试 请注意 Assert.True/False 翻转。
public class IsNumericTests
{
[Fact]
public void IsNumeric()
{
var value = 0;
Assert.True(value.IsNumeric());
}
[Fact]
public void IsObjectNumeric()
{
var value = 0;
var objValue = (object)value;
Assert.False(objValue.IsNumeric());
}
[Fact]
public void IsNumericAtRuntime()
{
var value = 0;
Assert.True(value.IsNumericAtRuntime());
}
[Fact]
public void IsObjectNumericAtRuntime()
{
var value = 0;
var objValue = (object)value;
Assert.True(objValue.IsNumericAtRuntime());
}
[Fact]
public void IsNullableNumeric()
{
int? value = 0;
Assert.True(value.IsNullableNumeric());
}
[Fact]
public void IsNullableNumericAsObject()
{
int? value = 0;
var objValue = (object)value;
Assert.True(objValue.IsNullableNumeric());
}
[Fact]
public void IsNullableNumericWhenNull()
{
int? value = null;
Assert.True(value.IsNullableNumeric());
}
[Fact]
public void IsNullableNumericWhenNullAsObject()
{
int? value = null;
var objValue = (object)value;
Assert.False(objValue.IsNullableNumeric());
}
[Fact]
public void IsNullableNumericWhenNotNumber()
{
string value = "test";
Assert.False(value.IsNullableNumeric());
}
[Fact]
public void IsNullableNumericWhenNullAndNotNumber()
{
Type? value = null;
Assert.False(value.IsNullableNumeric());
}
}
Run Code Online (Sandbox Code Playgroud)
基准/性能
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Jobs;
using HouseofCat.Extensions;
using System;
[MarkdownExporterAttribute.GitHub]
[MemoryDiagnoser]
[SimpleJob(runtimeMoniker: RuntimeMoniker.Net50 | RuntimeMoniker.NetCoreApp31)]
public class IsNumericBenchmark
{
public int IntValue = 1;
public long? LongValue = int.MaxValue;
public object ObjIntValue => (object)IntValue;
public object ObjLongValue => (object)LongValue;
[Benchmark(Baseline = true)]
public void IsNumeric()
{
IntValue.IsNumeric();
}
[Benchmark]
public void IsNumericAtRuntime()
{
ObjIntValue.IsNumericAtRuntime();
}
[Benchmark]
public void IsNullableNumeric()
{
LongValue.IsNullableNumeric();
}
}
Run Code Online (Sandbox Code Playgroud)
BenchmarkDotNet=v0.13.0, OS=Windows 10.0.18363.1621 (1909/November2019Update/19H2)
Intel Core i7-9850H CPU 2.60GHz, 1 CPU, 12 logical and 6 physical cores
.NET SDK=5.0.400-preview.21277.10
[Host] : .NET 5.0.7 (5.0.721.25508), X64 RyuJIT
.NET 5.0 : .NET 5.0.7 (5.0.721.25508), X64 RyuJIT
Job=.NET 5.0 Runtime=.NET 5.0
Run Code Online (Sandbox Code Playgroud)
方法 | 意思是 | 错误 | 标准差 | 比率 | 比率SD | 第0代 | 第一代 | 第2代 | 已分配 |
---|---|---|---|---|---|---|---|---|---|
是数字 | 16.65纳秒 | 0.104纳秒 | 0.087纳秒 | 1.00 | 0.00 | - | - | - | - |
运行时为数值 | 19.26纳秒 | 0.409纳秒 | 0.383纳秒 | 1.16 | 0.02 | 0.0038 | - | - | 24乙 |
是否可为空数值 | 58.65纳秒 | 0.692纳秒 | 0.647纳秒 | 3.53 | 0.04 | 0.0038 | - | - | 24乙 |
HouseofCat/Tesseract Github 存储库和 Nuget
在 C# 7 中,这种方法比 switch case on 提供了更好的性能,TypeCode
并且HashSet<Type>
:
public static bool IsNumeric(this object o) => o is byte || o is sbyte || o is ushort || o is uint || o is ulong || o is short || o is int || o is long || o is float || o is double || o is decimal;
Run Code Online (Sandbox Code Playgroud)
测试如下:
public static class Extensions
{
public static HashSet<Type> NumericTypes = new HashSet<Type>()
{
typeof(byte), typeof(sbyte), typeof(ushort), typeof(uint), typeof(ulong), typeof(short), typeof(int), typeof(long), typeof(decimal), typeof(double), typeof(float)
};
public static bool IsNumeric1(this object o) => NumericTypes.Contains(o.GetType());
public static bool IsNumeric2(this object o) => o is byte || o is sbyte || o is ushort || o is uint || o is ulong || o is short || o is int || o is long || o is decimal || o is double || o is float;
public static bool IsNumeric3(this object o)
{
switch (o)
{
case Byte b:
case SByte sb:
case UInt16 u16:
case UInt32 u32:
case UInt64 u64:
case Int16 i16:
case Int32 i32:
case Int64 i64:
case Decimal m:
case Double d:
case Single f:
return true;
default:
return false;
}
}
public static bool IsNumeric4(this object o)
{
switch (Type.GetTypeCode(o.GetType()))
{
case TypeCode.Byte:
case TypeCode.SByte:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
case TypeCode.Decimal:
case TypeCode.Double:
case TypeCode.Single:
return true;
default:
return false;
}
}
}
class Program
{
static void Main(string[] args)
{
var count = 100000000;
//warm up calls
for (var i = 0; i < count; i++)
{
i.IsNumeric1();
}
for (var i = 0; i < count; i++)
{
i.IsNumeric2();
}
for (var i = 0; i < count; i++)
{
i.IsNumeric3();
}
for (var i = 0; i < count; i++)
{
i.IsNumeric4();
}
//Tests begin here
var sw = new Stopwatch();
sw.Restart();
for (var i = 0; i < count; i++)
{
i.IsNumeric1();
}
sw.Stop();
Debug.WriteLine(sw.ElapsedMilliseconds);
sw.Restart();
for (var i = 0; i < count; i++)
{
i.IsNumeric2();
}
sw.Stop();
Debug.WriteLine(sw.ElapsedMilliseconds);
sw.Restart();
for (var i = 0; i < count; i++)
{
i.IsNumeric3();
}
sw.Stop();
Debug.WriteLine(sw.ElapsedMilliseconds);
sw.Restart();
for (var i = 0; i < count; i++)
{
i.IsNumeric4();
}
sw.Stop();
Debug.WriteLine(sw.ElapsedMilliseconds);
}
Run Code Online (Sandbox Code Playgroud)
.NET 7(撰写本文时为预览版 5)将引入
INumeric<>
将由 20 个内置类型实现的接口。
当添加其他数字类型时,检查此接口可能是面向未来的。
static bool IsNumeric(object o){
var numType = typeof(INumber<>);
return o.GetType().GetInterfaces().Any(iface =>
iface.IsGenericType && (iface.GetGenericTypeDefinition() == numType));
}
Run Code Online (Sandbox Code Playgroud)
目前在 .Net 7 预览版中实现此功能的类型有:
byte
char
decimal
double
Half
short
int
long
Int128
nint
BigInteger
Complex
NFloat
sbyte
float
ushort
uint
ulong
UInt128
nuint
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
67846 次 |
最近记录: |