มีวิธีตรวจสอบว่า. Net Type เป็นตัวเลขหรือไม่? ตัวอย่างเช่น: System.UInt32/UInt16/Doubleเป็นตัวเลขทั้งหมด ฉันต้องการหลีกเลี่ยงกรณีสวิตช์ยาวในไฟล์Type.FullName.
มีวิธีตรวจสอบว่า. Net Type เป็นตัวเลขหรือไม่? ตัวอย่างเช่น: System.UInt32/UInt16/Doubleเป็นตัวเลขทั้งหมด ฉันต้องการหลีกเลี่ยงกรณีสวิตช์ยาวในไฟล์Type.FullName.
คำตอบ:
ลองสิ่งนี้:
Type type = object.GetType();
bool isNumber = (type.IsPrimitiveImple && type != typeof(bool) && type != typeof(char));
ประเภทดั้งเดิม ได้แก่ Boolean, Byte, 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;
}
}
การใช้งาน:
int i = 32;
i.IsNumericType(); // True
string s = "Hello World";
s.IsNumericType(); // False
decimalประเภทจึงไม่ใช่ตัวเลข?
decimal มันเป็นตัวเลข เพียงเพราะมันไม่ใช่แบบดั้งเดิมไม่ได้หมายความว่ามันไม่ใช่ตัวเลข รหัสของคุณจำเป็นต้องคำนึงถึงสิ่งนี้
อย่าใช้สวิตช์ - เพียงแค่ใช้ชุด:
HashSet<Type> NumericTypes = new HashSet<Type>
{
typeof(decimal), typeof(byte), typeof(sbyte),
typeof(short), typeof(ushort), ...
};
แก้ไข: ข้อดีอย่างหนึ่งของสิ่งนี้ในการใช้รหัสประเภทคือเมื่อมีการนำประเภทตัวเลขใหม่เข้ามาใน. NET (เช่นBigIntegerและComplex ) จะปรับเปลี่ยนได้ง่ายในขณะที่ประเภทเหล่านั้นจะไม่ได้รับรหัสประเภท
switchก็ไม่ได้ผลTypeดังนั้นคุณจึงทำไม่ได้ แน่นอนคุณสามารถเปิดได้TypeCodeแต่นั่นเป็นเรื่องที่แตกต่างออกไป
ไม่มีโซลูชันใดที่คำนึงถึง 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));
}
ฉันรู้ว่าฉันสามารถเพิ่ม nullables ลงใน HashSet ของฉันได้ แต่วิธีนี้จะหลีกเลี่ยงอันตรายจากการลืมเพิ่ม Nullable เฉพาะในรายการของคุณ
private static HashSet<Type> NumericTypes = new HashSet<Type>
{
typeof(int),
typeof(int?),
...
};
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;
}
}
หมายเหตุเกี่ยวกับการเพิ่มประสิทธิภาพที่ถูกลบ (ดูความคิดเห็นของ 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;
}
return unchecked((uint)Type.GetTypeCode(type) - 5u) <= 10u; &&
โดยพื้นฐานแล้วโซลูชันของ Skeet แต่คุณสามารถใช้ซ้ำได้กับ Nullable types ดังนี้:
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);
}
}
แนวทางตามข้อเสนอของ 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;
}
}
}
ทำไมถึงเป็นเช่นนี้ ฉันต้องตรวจสอบว่าสิ่งที่ระบุType typeนั้นเป็นประเภทตัวเลขหรือไม่และไม่ใช่ว่าobject oตัวเลขนั้นเป็นตัวเลขหรือไม่
ด้วย C # 7 วิธีนี้ให้ประสิทธิภาพที่ดีกว่าการเปิดเคส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;
การทดสอบกำลังติดตาม:
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);
}
คุณสามารถใช้Type.IsPrimitiveจากนั้นจัดเรียงBooleanและCharประเภทต่างๆดังนี้:
bool IsNumeric(Type type)
{
return type.IsPrimitive && type!=typeof(char) && type!=typeof(bool);
}
แก้ไข : คุณอาจต้องการยกเว้นIntPtrและUIntPtrประเภทด้วยหากคุณไม่ถือว่าเป็นตัวเลข
decimalประเภทจึงไม่ใช่ตัวเลข?
พิมพ์นามสกุลด้วยการสนับสนุนประเภท null
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;
}
}
คำตอบสั้น ๆ : ไม่
คำตอบอีกต่อไป: ไม่
ความจริงก็คือประเภทต่างๆใน C # สามารถมีข้อมูลตัวเลขได้ เว้นแต่คุณจะรู้ว่าจะเกิดอะไรขึ้น (Int, Double ฯลฯ ) คุณจำเป็นต้องใช้ case statement "long"
ซึ่งอาจใช้ได้ผลเช่นกัน อย่างไรก็ตามคุณอาจต้องการติดตามด้วย TypeParse เพื่อโยนมันในแบบที่คุณต้องการในภายหลัง
public bool IsNumeric(object value)
{
float testValue;
return float.TryParse(value.ToString(), out testValue);
}
ดัดแปลงของเป้าบินและการแก้ไขปัญหา arviman ของใช้Generics, และReflectionC# v6.0
private static readonly HashSet<Type> m_numTypes = 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 myType )
{
var IsNumeric = false;
if( myType != null )
{
IsNumeric = m_numTypes.Contains( myType.GetType() );
}
return IsNumeric;
}
การใช้งานสำหรับ(T item):
if ( item.IsNumeric() ) {}
null ส่งคืนเท็จ
สวิตช์ช้าเล็กน้อยเพราะทุกครั้งวิธีการในสถานการณ์ที่เลวร้ายที่สุดจะผ่านทุกประเภท ฉันคิดว่าการใช้ Dictonary นั้นดีกว่าในสถานการณ์นี้คุณจะมีO(1):
public static class TypeExtensions
{
private static readonly HashSet<Type> NumberTypes = new HashSet<Type>();
static TypeExtensions()
{
NumberTypes.Add(typeof(byte));
NumberTypes.Add(typeof(decimal));
NumberTypes.Add(typeof(double));
NumberTypes.Add(typeof(float));
NumberTypes.Add(typeof(int));
NumberTypes.Add(typeof(long));
NumberTypes.Add(typeof(sbyte));
NumberTypes.Add(typeof(short));
NumberTypes.Add(typeof(uint));
NumberTypes.Add(typeof(ulong));
NumberTypes.Add(typeof(ushort));
}
public static bool IsNumber(this Type type)
{
return NumberTypes.Contains(type);
}
}
ลองTypeSupportแพคเกจ nuget สำหรับ C # มีการสนับสนุนสำหรับการตรวจจับประเภทตัวเลขทั้งหมด (ท่ามกลางคุณสมบัติอื่น ๆ อีกมากมาย):
var extendedType = typeof(int).GetExtendedType();
Assert.IsTrue(extendedType.IsNumericType);
น่าเสียดายที่ประเภทเหล่านี้ไม่มีอะไรเหมือนกันมากนักนอกจากประเภทมูลค่าทั้งหมด แต่เพื่อหลีกเลี่ยงการเปลี่ยนกรณีที่ยาวคุณสามารถกำหนดรายการแบบอ่านอย่างเดียวด้วยประเภทเหล่านี้ทั้งหมดจากนั้นตรวจสอบว่าประเภทที่กำหนดอยู่ในรายการหรือไม่
เป็นประเภทค่าทั้งหมด (ยกเว้นบูลและอาจเป็น enum) ดังนั้นคุณสามารถใช้:
bool IsNumberic(object o)
{
return (o is System.ValueType && !(o is System.Boolean) && !(o is System.Enum))
}
struct... ฉันไม่คิดว่านั่นคือสิ่งที่คุณต้องการ
แก้ไข:ฉันแก้ไขโค้ดด้านล่างให้มีประสิทธิภาพมากขึ้นจากนั้นจึงทำการทดสอบที่โพสต์โดย @Hugo กับมัน ความเร็วใกล้เคียงกับ IF ของ @ Hugo โดยใช้รายการสุดท้ายในลำดับ (ทศนิยม) อย่างไรก็ตามหากใช้รายการแรก 'ไบต์' เขาจะใช้เค้ก แต่คำสั่งมีความสำคัญอย่างชัดเจนเมื่อพูดถึงประสิทธิภาพ แม้ว่าการใช้โค้ดด้านล่างจะเขียนได้ง่ายกว่าและมีความสอดคล้องกับต้นทุนมากขึ้น แต่ก็ไม่สามารถบำรุงรักษาได้หรือสามารถพิสูจน์ได้ในอนาคต
ดูเหมือนว่าการเปลี่ยนจาก Type.GetTypeCode () เป็น Convert.GetTypeCode () เร่งประสิทธิภาพขึ้นอย่างมากประมาณ 25% VS Enum.Parse () ซึ่งช้ากว่า 10 เท่า
ฉันรู้ว่าโพสต์นี้เก่า แต่ถ้าใช้เมธอด TypeCode enum ง่ายที่สุด (และอาจถูกที่สุด) จะเป็นดังนี้:
public static bool IsNumericType(this object o)
{
var t = (byte)Convert.GetTypeCode(o);
return t > 4 && t < 16;
}
ให้นิยาม enum ต่อไปนี้สำหรับ TypeCode:
public enum TypeCode
{
Empty = 0,
Object = 1,
DBNull = 2,
Boolean = 3,
Char = 4,
SByte = 5,
Byte = 6,
Int16 = 7,
UInt16 = 8,
Int32 = 9,
UInt32 = 10,
Int64 = 11,
UInt64 = 12,
Single = 13,
Double = 14,
Decimal = 15,
DateTime = 16,
String = 18
}
ฉันยังไม่ได้ทดสอบอย่างละเอียด แต่สำหรับประเภทตัวเลข C # พื้นฐานดูเหมือนจะครอบคลุม อย่างไรก็ตามตามที่ @JonSkeet กล่าวไว้ enum นี้ไม่ได้รับการอัปเดตสำหรับประเภทเพิ่มเติมที่เพิ่มเข้ามาใน. NET บนท้องถนน
โอ๊ะ! อ่านคำถามผิด! ส่วนตัวจะม้วนกับเป้าของ
HRM, เสียงเหมือนคุณต้องการที่จะDoSomethingอยู่กับTypeข้อมูลของคุณ สิ่งที่คุณทำได้มีดังต่อไปนี้
public class MyClass
{
private readonly Dictionary<Type, Func<SomeResult, object>> _map =
new Dictionary<Type, Func<SomeResult, object>> ();
public MyClass ()
{
_map.Add (typeof (int), o => return SomeTypeSafeMethod ((int)(o)));
}
public SomeResult DoSomething<T>(T numericValue)
{
Type valueType = typeof (T);
if (!_map.Contains (valueType))
{
throw new NotSupportedException (
string.Format (
"Does not support Type [{0}].", valueType.Name));
}
SomeResult result = _map[valueType] (numericValue);
return result;
}
}