C# 如何判断类型是否为“简单”类型?即持有一个单一的价值
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/863881/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I tell if a type is a "simple" type? i.e. holds a single value
提问by Nathan Ridley
typeof(string).IsPrimitive == false
typeof(int).IsPrimitive == true
typeof(MyClass).IsClass == true
typeof(string).IsClass == true
typeof(string).IsByRef == false
typeof(MyClass).IsByRef == true // correction: should be false (see comments below)
I have a method that instantiates a new instance of T and, if it's a "complex" class, fills its properties from a set of source data values.
我有一个方法可以实例化 T 的新实例,如果它是一个“复杂”类,则从一组源数据值填充其属性。
(a) If T is a simple type (e.g. a string or an int or anything else similar), a quick conversion from the source data to T is to be performed.
(a) 如果 T 是一个简单类型(例如字符串或 int 或任何其他类似的东西),则将执行从源数据到 T 的快速转换。
(b) If T is a class (but not something simple like string), then I'll use Activator.CreateInstance and do a bit of reflection to populate the fields.
(b) 如果 T 是一个类(但不是像字符串这样简单的东西),那么我将使用 Activator.CreateInstance 并进行一些反射来填充字段。
Is there a quick and simple way to tell if I should use method (a) or method (b)? This logic will be used inside a generic method with T as the type argument.
有没有一种快速简单的方法来判断我应该使用方法(a)还是方法(b)?此逻辑将在以 T 作为类型参数的泛型方法中使用。
采纳答案by Stefan Steinegger
String is probably a special case.
字符串可能是一个特例。
I think I would do.....
我想我会做.....
bool IsSimple(Type type)
{
return type.IsPrimitive
|| type.Equals(typeof(string));
}
Edit:
编辑:
Sometimes you need to cover some more cases, like enums and decimals. Enums are a special kind of type in C#. Decimals are structs like any other. The problem with the structs is that they may be complex, they may be user defined types, they may be just a number. So you don't have any other chance than knowing them to differentiate.
有时您需要涵盖更多情况,例如枚举和小数。枚举是 C# 中的一种特殊类型。小数是与其他任何结构一样的结构。结构的问题在于它们可能很复杂,它们可能是用户定义的类型,它们可能只是一个数字。因此,除了了解它们进行区分之外,您没有任何其他机会。
bool IsSimple(Type type)
{
return type.IsPrimitive
|| type.IsEnum
|| type.Equals(typeof(string))
|| type.Equals(typeof(decimal));
}
Handling nullable counterparts are also a bit tricky. The nullable itself is a struct.
处理可空对应物也有点棘手。nullable 本身是一个结构体。
bool IsSimple(Type type)
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
// nullable type, check if the nested type is simple.
return IsSimple(type.GetGenericArguments()[0]);
}
return type.IsPrimitive
|| type.IsEnum
|| type.Equals(typeof(string))
|| type.Equals(typeof(decimal));
}
Test:
测试:
Assert.IsTrue(IsSimple(typeof(string)));
Assert.IsTrue(IsSimple(typeof(int)));
Assert.IsTrue(IsSimple(typeof(decimal)));
Assert.IsTrue(IsSimple(typeof(float)));
Assert.IsTrue(IsSimple(typeof(StringComparison))); // enum
Assert.IsTrue(IsSimple(typeof(int?)));
Assert.IsTrue(IsSimple(typeof(decimal?)));
Assert.IsTrue(IsSimple(typeof(StringComparison?)));
Assert.IsFalse(IsSimple(typeof(object)));
Assert.IsFalse(IsSimple(typeof(Point))); // struct in System.Drawing
Assert.IsFalse(IsSimple(typeof(Point?)));
Assert.IsFalse(IsSimple(typeof(StringBuilder))); // reference type
Note to .NET Core
.NET Core 的注意事项
As DucoJ points out in his answer, some of the used methods are not available on the class Type
in .NET core anymore.
正如 DucoJ 在他的回答中指出的那样,某些使用的方法Type
在 .NET 核心中的类上不再可用。
Fixed code (I hope it works, I couldn't try myself. Otherwise please comment):
固定代码(我希望它有效,我无法自己尝试。否则请发表评论):
bool IsSimple(Type type)
{
var typeInfo = type.GetTypeInfo();
if (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(Nullable<>))
{
// nullable type, check if the nested type is simple.
return IsSimple(typeInfo.GetGenericArguments()[0]);
}
return typeInfo.IsPrimitive
|| typeInfo.IsEnum
|| type.Equals(typeof(string))
|| type.Equals(typeof(decimal));
}
回答by Annath
Strings aren't primitives, if I recall correctly. even though there is a keyword for it, a string is an object. Your call to IsPrimitive will accurately tell you if something is a primitive.
如果我没记错的话,字符串不是原语。即使有一个关键字,字符串也是一个对象。您对 IsPrimitive 的调用将准确地告诉您某物是否是原始的。
回答by John Saunders
It may not matter, but it sounds like you're leaving out a few cases:
这可能无关紧要,但听起来您遗漏了一些情况:
- Complex types which have conversions
- Value types which don't have a parameterless constructor. Example below:
- 具有转换的复杂类型
- 没有无参数构造函数的值类型。下面的例子:
There are probably more, but I think you're partitioning the problem space in an overly-restrictive manner.
可能还有更多,但我认为您以过度限制的方式划分问题空间。
public class Person {
private string _name;
private int _age;
public Person(string name, int age) {_name = name; _age = age;}
// Remainder of value implementation
}
回答by Mike Vonn
There is a more general type than primitive, the ValueType encompasses a lot more than primitive, such as enums, decimal, and other such things ValueType. Below is a function I wrote to identify complex types, that may fit your needs.
有一种比原始类型更通用的类型,ValueType 包含的不仅仅是原始类型,例如枚举、十进制和其他类似的东西ValueType。下面是我编写的用于识别复杂类型的函数,它可能适合您的需求。
public static bool IsComplex(Type typeIn)
{
if (typeIn.IsSubclassOf(typeof(System.ValueType)) || typeIn.Equals(typeof(string))) //|| typeIn.IsPrimitive
return false;
else
return true;
}
回答by Capt Nasty
Sorry to resurrect a really old thread, but since this still ranks high on web searches in Google, want to get a more direct and effective solution added:
很抱歉复活了一个非常旧的线程,但由于这仍然在 Google 的网络搜索中排名靠前,因此希望添加一个更直接有效的解决方案:
if(System.Type.GetTypeCode(typeof(int)) == TypeCode.Object) {
// Do what you will...
}
回答by DucoJ
In Addition to Stefan Steinegger answer: In .NET Core the .IsPrimitive etc. are no longer members of Type, they are now members of TypeInfo. So his solution will then become:
除了 Stefan Steinegger 的回答:在 .NET Core 中,.IsPrimitive 等不再是 Type 的成员,它们现在是 TypeInfo 的成员。所以他的解决方案将变成:
bool IsSimple(TypeInfo type)
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
// nullable type, check if the nested type is simple.
return IsSimple((type.GetGenericArguments()[0]).GetTypeInfo());
}
return type.IsPrimitive
|| type.IsEnum
|| type.Equals(typeof(string))
|| type.Equals(typeof(decimal));
}
回答by Shyam Kumar
Modified Mauser's answer a little bit added a method to check whether a property is an collection.
修改了毛瑟的答案,添加了一个方法来检查属性是否是集合。
public static class TypeExtensions { public static bool IsComplex(this Type type) { return !type.IsValueType && type != typeof(string); } public static bool IsCollection(this Type type) { var collectionTypeName = typeof(ICollection<>).Name; return type.Name == collectionTypeName || type.GetInterface(collectionTypeName) != null; } }
public static class TypeExtensions { public static bool IsComplex(this Type type) { return !type.IsValueType && type != typeof(string); } public static bool IsCollection(this Type type) { var collectionTypeName = typeof(ICollection<>).Name; return type.Name == collectionTypeName || type.GetInterface(collectionTypeName) != null; } }
Here inside IsCollection(..) we can even keep IEnumerable, but string also inherit IEnumerable. so if you are using IEnumerable, add a check for string also!
在 IsCollection(..) 中,我们甚至可以保留 IEnumerable,但是 string 也继承了 IEnumerable。因此,如果您使用的是 IEnumerable,还要添加对字符串的检查!
public static class TypeExtensions
{
public static bool IsComplex(this Type type)
{
return !type.IsValueType && type != typeof(string);
}
public static bool IsCustomComplex(this Type type)
{
var elementType = type.GetCustomElementType();
return elementType != null && elementType.IsComplex();
}
public static Type GetCustomElementType(this Type type, object value)
{
return value != null
? value.GetType().GetCustomElementType()
: type.GetCustomElementType();
}
public static Type GetCustomElementType(this Type type)
{
return type.IsCollection()
? type.IsArray
? type.GetElementType()
: type.GetGenericArguments()[0]
: type;
}
public static bool IsCustomComplex(this Type type, object value)
{
return value != null
? value.GetType().IsCustomComplex()
: type.IsCustomComplex();
}
public static bool IsCollection(this Type type)
{
var collectionTypeName = typeof(IEnumerable<>).Name;
return (type.Name == collectionTypeName || type.GetInterface(typeof(IEnumerable<>).Name) != null ||
type.IsArray) && type != typeof(string);
}
public static bool HasDefaultConstructor(this Type type)
{
return type.IsValueType || type.GetConstructor(Type.EmptyTypes) != null;
}
}