Belirli bir .Net Türünün bir sayı olup olmadığını belirlemenin bir yolu var mı? Örneğin: System.UInt32/UInt16/Doublehepsi sayıdır. Üzerinde uzun bir geçiş durumundan kaçınmak istiyorum Type.FullName.
Belirli bir .Net Türünün bir sayı olup olmadığını belirlemenin bir yolu var mı? Örneğin: System.UInt32/UInt16/Doublehepsi sayıdır. Üzerinde uzun bir geçiş durumundan kaçınmak istiyorum Type.FullName.
Yanıtlar:
Bunu dene:
Type type = object.GetType();
bool isNumber = (type.IsPrimitiveImple && type != typeof(bool) && type != typeof(char));
İlkel türler Boolean, Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, Char, Double ve Single'dır.
Alarak Guillaume'nin çözümü biraz daha:
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;
}
}
Kullanım:
int i = 32;
i.IsNumericType(); // True
string s = "Hello World";
s.IsNumericType(); // False
decimaltip sayısal değil mi?
decimal olduğunu sayısal. İlkel olmaması, sayısal olmadığı anlamına gelmez. Kodunuzun bunu hesaba katması gerekir.
Anahtar kullanmayın - sadece bir set kullanın:
HashSet<Type> NumericTypes = new HashSet<Type>
{
typeof(decimal), typeof(byte), typeof(sbyte),
typeof(short), typeof(ushort), ...
};
DÜZENLEME: Bunun bir tür kodu kullanmaya göre bir avantajı, .NET'e yeni sayısal türler eklendiğinde (ör. BigInteger ve Karmaşık ) ayarlamanın kolay olmasıdır - oysa bu türler bir tür kodu almaz .
switchSadece üzerinde çalışmıyor Type, bu yüzden yapamazsınız. TypeCodeElbette açabilirsiniz , ancak bu farklı bir konu.
Çözümlerin hiçbiri Nullable'ı hesaba katmaz.
Jon Skeet'in çözümünü biraz değiştirdim:
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));
}
Boş değerlerin kendisini HashSet'ime ekleyebileceğimi biliyorum. Ancak bu çözüm, listenize belirli bir Nullable eklemeyi unutma tehlikesini ortadan kaldırır.
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;
}
}
Kaldırılan optimizasyon hakkında not (enzi yorumlarına bakın)
Ve gerçekten optimize etmek istiyorsanız (okunabilirliği kaybetmek ve biraz güvenlik ...):
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;nedenle tarafından tanıtılan dalı kaldırmak olacaktır &&.
Temelde Skeet'in çözümü, ancak bunu Nullable türlerle aşağıdaki gibi yeniden kullanabilirsiniz:
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'in önerisine dayanan yaklaşım , SFun28'inNullable türler için dahili tip kontrolü ile geliştirilmiş :
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;
}
}
}
Neden bu? Type typeVerilenin sayısal bir tür olup olmadığını kontrol etmem gerekiyordu , keyfi object obir sayısal mı?
C # 7 ile bu yöntem bana durumu açmaktan daha iyi performans veriyor TypeCodeve 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;
Testler şu şekildedir:
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'i kullanabilir ve ardından Booleanve Chartürlerini şu şekilde sıralayabilirsiniz :
bool IsNumeric(Type type)
{
return type.IsPrimitive && type!=typeof(char) && type!=typeof(bool);
}
DÜZENLEME : Sayısal olmadıklarını düşünmüyorsanız IntPtrve UIntPtrtürlerini de hariç tutmak isteyebilirsiniz .
decimaltip sayısal değil mi?
Boş tip destekli uzantı yazın.
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;
}
}
Modifiye skeet en ve arviman çözümü kullanan Generics, Reflectionve C# 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)
};
Bunu takiben:
public static bool IsNumeric<T>( this T myType )
{
var IsNumeric = false;
if( myType != null )
{
IsNumeric = m_numTypes.Contains( myType.GetType() );
}
return IsNumeric;
}
Kullanım için (T item):
if ( item.IsNumeric() ) {}
null yanlış döndürür.
Geçiş biraz yavaştır, çünkü her seferinde en kötü durumdaki yöntemler her türden geçecektir. Bence, Dictonary kullanmak daha güzel, bu durumda sahip olacaksınız 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);
}
}
C # için TypeSupport nuget paketini deneyin . Tüm sayısal türleri tespit etme desteği vardır (diğer birçok özelliğin yanı sıra):
var extendedType = typeof(int).GetExtendedType();
Assert.IsTrue(extendedType.IsNumericType);
Maalesef, bu türlerin hepsinin değer türleri dışında çok fazla ortak yanı yoktur. Ancak uzun bir geçiş durumunu önlemek için tüm bu türlerle salt okunur bir liste tanımlayabilir ve ardından verilen türün listenin içinde olup olmadığını kontrol edebilirsiniz.
Bunların hepsi değer türleridir (bool ve belki enum hariç). Yani şunları kullanabilirsiniz:
bool IsNumberic(object o)
{
return (o is System.ValueType && !(o is System.Boolean) && !(o is System.Enum))
}
struct... İstediğinizin bu olduğunu sanmıyorum.
DÜZENLEME: Aşağıdaki kodu daha performanslı olması için değiştirdim ve ardından @Hugo tarafından gönderilen testleri buna karşı yürüttüm. Hızlar, dizisindeki son öğeyi (Ondalık) kullanan @ Hugo'nun IF ile hemen hemen aynı. Bununla birlikte, ilk öğe 'bayt'ı kullanıyorsa, pastayı alır, ancak performans söz konusu olduğunda sipariş açıkça önemlidir. Aşağıdaki kodu kullanmak daha kolay ve maliyeti açısından daha tutarlı olsa da, yine de sürdürülemez veya gelecekte kanıtlanabilir değildir.
Görünüşe göre Type.GetTypeCode () 'den Convert.GetTypeCode ()' a geçiş, performansı önemli ölçüde hızlandırdı, yaklaşık% 25, VS Enum.Parse (), bu 10 kat daha yavaş gibiydi.
Bu yazı eski olduğunu biliyorum ama IF TypeCode enum yöntemi kullanılarak, en kolay (ve muhtemelen en ucuz) böyle bir şey olacaktır:
public static bool IsNumericType(this object o)
{
var t = (byte)Convert.GetTypeCode(o);
return t > 4 && t < 16;
}
TypeCode için aşağıdaki enum tanımı verildiğinde:
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
}
Tam olarak test etmedim, ancak temel C # sayısal türleri için bu onu kapsıyor gibi görünüyor. Ancak, @JonSkeet'in de belirttiği gibi, bu numaralandırma yolda .NET'e eklenen ek türler için güncellenmez.
oops! Soruyu yanlış okuyun! Şahsen, Skeet's ile yuvarlanırdı .
hrm, senin gibi sesler istiyoruz DoSomethingüzerindeki Typeverilerin. Yapabileceğin şey şudur
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;
}
}