주어진 .Net 유형이 숫자인지 여부를 확인하는 방법이 있습니까? 예 : System.UInt32/UInt16/Double모두 숫자입니다. .NET에서 긴 스위치 케이스를 피하고 싶습니다 Type.FullName.
주어진 .Net 유형이 숫자인지 여부를 확인하는 방법이 있습니까? 예 : System.UInt32/UInt16/Double모두 숫자입니다. .NET에서 긴 스위치 케이스를 피하고 싶습니다 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입니다.
촬영 기욤의 솔루션을 조금 더 :
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));
}
내 HashSet에 nullables 자체를 추가 할 수 있다는 것을 알고 있습니다. 그러나이 솔루션은 특정 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;
}
}
제거 된 최적화에 대한 참고 사항 (엔지 주석 참조)
그리고 정말로 최적화하고 싶다면 (가독성과 약간의 안전성을 잃습니다 ...) :
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 유형과 함께 재사용 할 수 있습니다.
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);
}
}
유형에 대한 SFun28의 내부 유형 검사 를 통해 강화 된 Philip의 제안 에 기반한 접근 방식 :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유형이 숫자가 아니에요?
널 유형을 지원하는 유형 확장.
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;
}
}
수정 스키트의 및 arviman의 솔루션을 활용 Generics, Reflection하고 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)
};
뒤에 :
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);
}
}
C # 용 TypeSupport 너겟 패키지를 사용 해보세요 . 다른 많은 기능 중에서 모든 숫자 유형을 감지 할 수 있도록 지원합니다.
var extendedType = typeof(int).GetExtendedType();
Assert.IsTrue(extendedType.IsNumericType);
모두 값 유형입니다 (boool 및 enum 제외). 따라서 다음을 간단히 사용할 수 있습니다.
bool IsNumberic(object o)
{
return (o is System.ValueType && !(o is System.Boolean) && !(o is System.Enum))
}
struct... 나는 그것이 당신이 원하는 것이라고 생각하지 않습니다.
편집하다: 글쎄, 나는 더 성능이 좋도록 아래 코드를 수정 한 다음 @Hugo가 게시 한 테스트를 실행했습니다. 속도는 시퀀스의 마지막 항목 (십진수)을 사용하는 @Hugo의 IF와 거의 비슷합니다. 그러나 첫 번째 항목 '바이트'를 사용하면 케이크를 가져 가지만 성능과 관련하여 분명히 순서가 중요합니다. 아래 코드를 사용하는 것이 작성하기 쉽고 비용면에서 더 일관 적이지만 유지 관리가 가능하거나 미래를 보장 할 수는 없습니다.
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;
}
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에서 언급했듯이이 열거 형은 향후 .NET에 추가되는 추가 유형에 대해 업데이트되지 않습니다.
이런! 질문을 오해하십시오! 개인적으로 Skeet의 .
흠, 데이터 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;
}
}