如何判断 IEnumerable是来自 IEnumerable?
我有一个带有 IEnumerable
参数的方法。T
可以是内置 .NET 之一类型,例如 int
或 string
或这样的自定义类:
class MyClass
{
public string Foo{ get; set; }
public int Bar{ get; set; }
}
如果 T
是其中之一,我如何以编程方式识别内置的类型?
我知道我可以做这样的事情:
switch (typeof(T).Name.ToLower())
{
case "int":
case "string":
case "...": // and so on...
Console.WriteLine("It's a built-in type!");
break;
default:
Console.WriteLine("It's a custom class!");
break;
}
...但一定有一个更短/更简单的方法,对吗?
编辑:
好的,伙计们,非常感谢你们迄今为止的回答。
但我仍然不确定哪一个最适合我的情况。
我真正想做的是:
我正在编写一个库,将 IEnumerable
转换为 ADODB.Recordsets
。
在每次转换开始时,我需要创建一个空的 Recordset 并向其中添加字段。
如果 T
是自定义类,我必须 循环遍历其属性,并在 Recordset 中为 T
的每个属性创建一个字段(包含属性的名称和类型)。
但只有当 T
是自定义类时,循环属性才能正常工作。
例如,它的 T
是一个 string
,我得到了 string
的属性(Chars
和 长度
),在这种情况下对我来说没有用。
这意味着仅检查它是否是原始类型是不够的 - 我还需要识别诸如 DateTime
和 GUID
之类的东西,而且可能还有更多。
(我必须承认,我没有注意到 DateTime
不在内置类型列表中)。
所以我想我真正想要的是:
判断 T
是否具有我可以循环的用户定义属性。
(无论它是否根本没有属性,例如 int
,或者我不关心的属性,例如 string 有)
这有道理吗?
但是,我仍然不确定选择哪个答案。
driis' 和 Jon Skeet 的答案都意味着我基本上必须列出很多类型(Jon 的答案比 driis 的答案更多)。
目前,我倾向于选择 Ron Sijm 的答案(尽管人们显然更喜欢其他答案),因为我想简单地检查 "System."
是做我想做的事情的最短方法,即使如果它看起来不那么优雅......
I have a method with an IEnumerable<T>
parameter.T
can be one of the built-in .NET types like int
or string
or a custom class like this:
class MyClass
{
public string Foo{ get; set; }
public int Bar{ get; set; }
}
How can I recognize programmatically if T
is one of the built-in types?
I know that I can do something like this:
switch (typeof(T).Name.ToLower())
{
case "int":
case "string":
case "...": // and so on...
Console.WriteLine("It's a built-in type!");
break;
default:
Console.WriteLine("It's a custom class!");
break;
}
...but there must be a shorter/simpler way, right?
EDIT:
Okay guys, thank you very much for the answers so far.
But I'm still not sure which one is the best for my situation.
What I actually want to do is this:
I'm writing a library to convert IEnumerable<T>s
into ADODB.Recordsets
.
At the beginning of each conversion, I need to create an empty Recordset and add fields to it.
If T
is a custom class, I have to loop through its properties and create a field in the Recordset for each property of T
(with the property's name and type).
But looping through the properties only works properly if T
is a custom class.
For example, it T
is a string
, I get the properties of the string
(Chars
and Length
), which are of no use for me in this case.
This means that only checking if it's a primitive type is not enough - I need to recognize things like DateTime
and GUID
as well, and there are probably even more.
(I have to admit, I didn't notice that DateTime
is not in the list of built-in types).
So I guess what I actually want is:
Tell if T
has user-defined properties which I can loop, or not.
(no matter if it has no properties at all like int
, or properties which I don't care about like string
has)
Does this make sense?
However, I'm still not sure which answer to pick.
driis' and Jon Skeet's answer both mean that I basically have to list a lot of types (more in Jon's answer than driis' answer).
At the moment, I tend to pick Ron Sijm's answer (even though people apparently liked the other answers more), because I guess simply checking "System."
is the shortest way to do what I want, even if it does not look, well, that elegant...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
这取决于您定义的“内置类型”。在许多情况下,您可以查看类型是原始类型还是字符串。 (因为字符串被认为是“内置的”,但它不是原语)。
如果您对这些原语感到满意(来自 MSDN):
请记住,类型名
int
只是Int32
的 C# 别名。编辑
为了确定可直接用作记录集中字段的类型,我可能会首先查看 IsPrimitive,然后使用 ADO 直接支持的其他“单值类型”的 HashSet。对包括
Guid
、Decimal
、string
和DateTime
在内的类型进行集体讨论。我不认为还有太多其他人,但我可能是错的。当然,直接驻留在 System 命名空间中的类型是一种简单的方法,但是当有人第一次向您传递
System.AppDomain
或System.Uri
时,您就会遇到麻烦>。基本上,如果您查看 System 命名空间中的内容,就会发现绝大多数类型不应该尝试放入单个字段中。It depends on what you define as "built-in types". In many cases, you could look at whether the type is primitive, or string. (Because string is considered "built-in", but it is not a primitive).
This works, if you are satisfied with these primitives (from MSDN):
Remember that the typename
int
is just a C# alias forInt32
.Edit
For determining types that can be used as a field in a recordset directly, I would probably look at IsPrimitive first, and then have a HashSet of other "single-valued types" that are directly supported by ADO. A brainstorm of types to include turns up
Guid
,Decimal
,string
andDateTime
. I don't think there are too many others, but I might be wrong.Sure, types that reside directly in the System namespace would be a simple approach, but you will be in trouble the first time someone passes you a
System.AppDomain
or aSystem.Uri
. Basically, if you look at what's in the System namespace, the vast majority of types is not something you should try to put in a single field.您确定的“内置类型”可能是特定于上下文的 - 例如,您列出了 C# 语言中内置的类型,但这确实是 C# 特定的。例如,它包括十进制(不是 CLR 基元类型),但不包括日期时间(其他语言可以明确支持)。
因此,我只需使用您适当创建的
HashSet
:What you determine to be a "built-in type" is likely to be context-specific - you've listed the types built into the C# language, for example, but that really is specific to C#. It includes
decimal
(which isn't a CLR primitive type) for example, but notDateTime
(which other languages could support explicitly).So, I'd just use a
HashSet<Type>
which you create appropriately:您可以使用
(typeof(T).FullName.StartsWith("System."))
You could use
(typeof(T).FullName.StartsWith("System."))
我喜欢使用 Type.GetTypeCode() 来处理数据库“基元”。您可以有一个简单的条件来告诉您它是否是数据库原语,如下所示:
GetTypeCode()
的返回类型是TypeCode
枚举,它将返回以下枚举之一如果类型匹配,则返回 TypeCode.Object 枚举值,否则返回 TypeCode.Object 枚举值:值得注意的遗漏是
Guid
、DateTimeOffset
和可为 null 的类型(尽管您可以使用typeof(T).GetGenericTypeDefinition() == typeof(Nullable<>)
检查对象是否可为 null,然后使用Nullable.GetUnderlyingType(typeof(T))
方法获取不可为 null 的类型,该类型将使用GetTypeCode()
。I like to use the
Type.GetTypeCode()
for dealing with database 'primitives'. You can have a simple condition that tells you if it's a database primitive as so:The return type of
GetTypeCode()
is theTypeCode
enumeration which will return one of the below enumeration values if the type matches, otherwise it will return theTypeCode.Object
enumeration value:Notable omissions are
Guid
,DateTimeOffset
, and nullable types (although you can usetypeof(T).GetGenericTypeDefinition() == typeof(Nullable<>)
to check if an object is nullable and then useNullable.GetUnderlyingType(typeof(T))
method to get a non-nullable type which will work withGetTypeCode()
.我很难决定我是否更喜欢 driis 的答案还是 Jon 的答案,但最终我选择接受 Jon 的答案。
对于任何感兴趣的人,我想详细说明一下为什么我认为这个答案对我来说是最好的解决方案:
乍一看,我更喜欢
.IsPrimitive
,而不是用所有内容填充HashSet
类型。但是,一旦提到像
string
和datetime
这样的特殊情况,很明显我不会使用像if (typeof(T) 这样的简短解决方案.IsPrimitive) 无论如何。
因此,我更多地考虑了我的实际用例(从
IEnumerable
转换为ADODB.Recordset
),并且我注意到对于 CLR 类型到 ADO 类型的实际转换,无论如何,我都需要两种类型的列表。(要知道
Int16
需要转换为ADODB.DataTypeEnum.adSmallInt
,等等)所以最后我做了类似 Jon 建议的事情,但我使用
Dictionary
来保存我支持的 CLR 类型和相应的 ADO 类型:稍后我可以使用它来将 POCO 属性转换为 ADO 字段的实际工作。
我还可以在开始转换之前检查
IEnumerable
的T
,因为如果TryGetAdoTypeForClrType(typeof(T), ...) 找到一些东西,那么
T
不能是 POCO / 自定义类。如果您出于其他原因需要从
IEnumerable
中区分IEnumerable
,这可能不是最优雅的解决方案,但我认为它是在至少是现在我的用例的最佳解决方案。I had a hard time deciding if I like driis' or Jon's answer better, but at the end I chose to accept Jon's answer.
For anyone interested, I wanted to elaborate a bit on why I considered this answer the best solution for me:
At first glance I liked
.IsPrimitive
better than populating aHashSet
with all the types.But once the special cases like
string
anddatetime
were mentioned, it was clear that I wouldn't get away with a short solution likeif (typeof(T).IsPrimitive)
anyway.So I thought more about my actual use case (converting from
IEnumerable<T>
toADODB.Recordset
) and I noticed that for the actual conversion of CLR types to ADO types, I would need lists of both kind of types anyway.(to know that an
Int16
needs to be converted into anADODB.DataTypeEnum.adSmallInt
, and so on)So at the end I did something similar like Jon suggested, but I used a
Dictionary
to hold my supported CLR types and the corresponding ADO types:I can use this later for the actual work of converting my POCO properties to ADO fields.
And I can also check the
T
of anIEnumerable<T>
before I start converting, because ifTryGetAdoTypeForClrType(typeof(T), ...)
finds something, thenT
can't be a POCO / custom class.This might not be the most elegant solution if you need to tell an
IEnumerable<int>
from anIEnumerable<MyClass>
for other reasons than I do, but I think it's at least the best solution for my use case now.