如何判断 IEnumerable是来自 IEnumerable

发布于 2024-12-14 00:06:39 字数 1903 浏览 0 评论 0原文

我有一个带有 IEnumerable 参数的方法。
T 可以是内置 .NET 之一类型,例如 intstring 或这样的自定义类:

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;
}

...但一定有一个更短/更简单的方法,对吗?


编辑:

好的,伙计们,非常感谢你们迄今为止的回答。
但我仍然不确定哪一个最适合我的情况。

我真正想做的是:
我正在编写一个库,将 IEnumerables 转换为 ADODB.Recordsets
在每次转换开始时,我需要创建一个空的 Recordset 并向其中添加字段。

如果 T 是自定义类,我必须 循环遍历其属性,并在 Recordset 中为 T 的每个属性创建一个字段(包含属性的名称和类型)。

但只有当 T 是自定义类时,循环属性才能正常工作。
例如,它的 T 是一个 string,我得到了 string 的属性(Chars长度),在这种情况下对我来说没有用。

这意味着仅检查它是否是原始类型是不够的 - 我还需要识别诸如 DateTimeGUID 之类的东西,而且可能还有更多。
(我必须承认,我没有注意到 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

冷月断魂刀 2024-12-21 00:06:39

这取决于您定义的“内置类型”。在许多情况下,您可以查看类型是原始类型还是字符串。 (因为字符串被认为是“内置的”,但它不是原语)。

if (typeof(T).IsPrimitive || typeof(T) == typeof(string))
    Console.WriteLine("It's a built-in type");

如果您对这些原语感到满意(来自 MSDN):

基本类型有 Boolean、Byte、SByte、Int16、UInt16、Int32、
UInt32、Int64、UInt64、IntPtr、UIntPtr、Char、Double 和 Single。

请记住,类型名 int 只是 Int32 的 C# 别名。

编辑

为了确定可直接用作记录集中字段的类型,我可能会首先查看 IsPrimitive,然后使用 ADO 直接支持的其他“单值类型”的 HashSet。对包括 GuidDecimalstringDateTime 在内的类型进行集体讨论。我不认为还有太多其他人,但我可能是错的。

当然,直接驻留在 System 命名空间中的类型是一种简单的方法,但是当有人第一次向您传递 System.AppDomainSystem.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).

if (typeof(T).IsPrimitive || typeof(T) == typeof(string))
    Console.WriteLine("It's a built-in type");

This works, if you are satisfied with these primitives (from MSDN):

The primitive types are Boolean, Byte, SByte, Int16, UInt16, Int32,
UInt32, Int64, UInt64, IntPtr, UIntPtr, Char, Double, and Single.

Remember that the typename intis just a C# alias for Int32.

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 and DateTime. 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 a System.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.

傾城如夢未必闌珊 2024-12-21 00:06:39

您确定的“内置类型”可能是特定于上下文的 - 例如,您列出了 C# 语言中内置的类型,但这确实是 C# 特定的。例如,它包括十进制(不是 CLR 基元类型),但不包括日期时间(其他语言可以明确支持)。

因此,我只需使用您适当创建的 HashSet

private static readonly HashSet<Type> BuiltInTypes = new HashSet<Type>
{
    typeof(object), typeof(string), typeof(byte), typeof(sbyte),
    // etc
};

// Then:
if (BuiltInTypes.Contains(typeof(T)))
{
    Console.WriteLine("It's a built-in type!");
}
else
{
    Console.WriteLine("It's a custom class!");
}

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 not DateTime (which other languages could support explicitly).

So, I'd just use a HashSet<Type> which you create appropriately:

private static readonly HashSet<Type> BuiltInTypes = new HashSet<Type>
{
    typeof(object), typeof(string), typeof(byte), typeof(sbyte),
    // etc
};

// Then:
if (BuiltInTypes.Contains(typeof(T)))
{
    Console.WriteLine("It's a built-in type!");
}
else
{
    Console.WriteLine("It's a custom class!");
}
咋地 2024-12-21 00:06:39

您可以使用 (typeof(T).FullName.StartsWith("System."))

You could use (typeof(T).FullName.StartsWith("System."))

沧桑㈠ 2024-12-21 00:06:39

我喜欢使用 Type.GetTypeCode() 来处理数据库“基元”。您可以有一个简单的条件来告诉您它是否是数据库原语,如下所示:

bool isDBPrimitive = Type.GetTypeCode(typeof(T)) != Object;

GetTypeCode() 的返回类型是 TypeCode 枚举,它将返回以下枚举之一如果类型匹配,则返回 TypeCode.Object 枚举值,否则返回 TypeCode.Object 枚举值:

DBNull
布尔
查尔
字节
字节
整数16
UInt16
Int32
UInt32
Int64
UInt64
单身

十进制
日期时间
字符串

值得注意的遗漏是 GuidDateTimeOffset 和可为 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:

bool isDBPrimitive = Type.GetTypeCode(typeof(T)) != Object;

The return type of GetTypeCode() is the TypeCode enumeration which will return one of the below enumeration values if the type matches, otherwise it will return the TypeCode.Object enumeration value:

DBNull
Boolean
Char
SByte
Byte
Int16
UInt16
Int32
UInt32
Int64
UInt64
Single
Double
Decimal
DateTime
String

Notable omissions are Guid, DateTimeOffset, and nullable types (although you can use typeof(T).GetGenericTypeDefinition() == typeof(Nullable<>) to check if an object is nullable and then use Nullable.GetUnderlyingType(typeof(T)) method to get a non-nullable type which will work with GetTypeCode().

述情 2024-12-21 00:06:39

我很难决定我是否更喜欢 driis 的答案还是 Jon 的答案,但最终我选择接受 Jon 的答案。

对于任何感兴趣的人,我想详细说明一下为什么我认为这个答案对我来说是最好的解决方案:

乍一看,我更喜欢 .IsPrimitive ,而不是用所有内容填充 HashSet类型。
但是,一旦提到像 stringdatetime 这样的特殊情况,很明显我不会使用像 if (typeof(T) 这样的简短解决方案.IsPrimitive) 无论如何。

因此,我更多地考虑了我的实际用例(从 IEnumerable 转换为 ADODB.Recordset),并且我注意到对于 CLR 类型到 ADO 类型的实际转换,无论如何,我都需要两种类型的列表。
(要知道 Int16 需要转换为 ADODB.DataTypeEnum.adSmallInt,等等)

所以最后我做了类似 Jon 建议的事情,但我使用 Dictionary 来保存我支持的 CLR 类型相应的 ADO 类型:

internal static class DataTypes
{
    private static readonly Dictionary<Type, ADODB.DataTypeEnum> Types
        = new Dictionary<Type, ADODB.DataTypeEnum>()
        {
            { typeof(Boolean), ADODB.DataTypeEnum.adBoolean },
            { typeof(DateTime), ADODB.DataTypeEnum.adDate },
            // and so on...
        };

    public static bool TryGetAdoTypeForClrType(Type clrType, out ADODB.DataTypeEnum adoType)
    {
        return Types.TryGetValue(clrType, out adoType);
    }
}

稍后我可以使用它来将 POCO 属性转换为 ADO 字段的实际工作。

我还可以在开始转换之前检查 IEnumerableT,因为如果 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 a HashSet with all the types.
But once the special cases like stringand datetime were mentioned, it was clear that I wouldn't get away with a short solution like if (typeof(T).IsPrimitive) anyway.

So I thought more about my actual use case (converting from IEnumerable<T> to ADODB.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 an ADODB.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:

internal static class DataTypes
{
    private static readonly Dictionary<Type, ADODB.DataTypeEnum> Types
        = new Dictionary<Type, ADODB.DataTypeEnum>()
        {
            { typeof(Boolean), ADODB.DataTypeEnum.adBoolean },
            { typeof(DateTime), ADODB.DataTypeEnum.adDate },
            // and so on...
        };

    public static bool TryGetAdoTypeForClrType(Type clrType, out ADODB.DataTypeEnum adoType)
    {
        return Types.TryGetValue(clrType, out adoType);
    }
}

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 an IEnumerable<T> before I start converting, because if TryGetAdoTypeForClrType(typeof(T), ...) finds something, then T can't be a POCO / custom class.

This might not be the most elegant solution if you need to tell an IEnumerable<int> from an IEnumerable<MyClass> for other reasons than I do, but I think it's at least the best solution for my use case now.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文