You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过反射区分C#中的类与原子类型(如string、int等)

解决区分原子类型与自定义类的反射方案

针对你在实现ConvertObjectCollectionToParameter泛型方法时遇到的问题——无法通过IsClass区分string和自定义类,这里提供两种基于反射的优雅判断方式:

方法一:明确区分值类型、string与其他引用类型

直接通过类型特性判断,将值类型(包括DateTime、decimal这类非primitive的struct)和string归为原子类型,其余引用类型视为复杂类:

private bool IsAtomicType<T>()
{
    Type type = typeof(T);
    // 值类型均视为原子类型
    if (type.IsValueType)
        return true;
    // string是引用类型但属于原子范畴
    if (type == typeof(string))
        return true;
    // 剩余引用类型为复杂类
    return false;
}

方法二:利用TypeCode枚举判断

通过Type.GetTypeCode获取类型的枚举值,排除TypeCode.Object(对应自定义类、数组等复杂类型),其余均为原子类型:

private bool IsAtomicType<T>()
{
    TypeCode typeCode = Type.GetTypeCode(typeof(T));
    // TypeCode.Object对应复杂引用类型,其余为原子类型
    return typeCode != TypeCode.Object;
}

在泛型方法中应用判断

将上述判断整合到你的ConvertObjectCollectionToParameter方法中,分别处理原子类型集合和复杂类集合:

public SqlParameter ConvertObjectCollectionToParameter<T>(IEnumerable<T> collection, string parameterName)
{
    DataTable dataTable = new DataTable();
    string tvpTypeName;

    if (IsAtomicType<T>())
    {
        // 原子类型集合:创建单列DataTable
        dataTable.Columns.Add("Value", typeof(T));
        tvpTypeName = "dbo.AtomicTypeTableType"; // 替换为你的TVP类型名
        foreach (T item in collection)
        {
            dataTable.Rows.Add(item ?? DBNull.Value);
        }
    }
    else
    {
        // 复杂类集合:根据类属性创建多列DataTable
        PropertyInfo[] properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
        foreach (PropertyInfo prop in properties)
        {
            dataTable.Columns.Add(prop.Name, prop.PropertyType);
        }
        tvpTypeName = $"dbo.{typeof(T).Name}TableType"; // 替换为你的TVP类型名
        foreach (T item in collection)
        {
            DataRow row = dataTable.NewRow();
            foreach (PropertyInfo prop in properties)
            {
                row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
            }
            dataTable.Rows.Add(row);
        }
    }

    return new SqlParameter(parameterName, SqlDbType.Structured)
    {
        Value = dataTable,
        TypeName = tvpTypeName
    };
}

补充说明

  • 方法一逻辑直观,可灵活扩展(比如需要排除自定义struct时,可添加type.IsPrimitive判断);
  • 方法二更简洁,自动覆盖所有.NET内置原子类型,无需手动枚举;
  • 若你的场景中需要将Guid、DateTimeOffset等特殊值类型也视为原子类型,两种方法均无需额外修改,因为它们都属于值类型或对应非Object的TypeCode。

内容的提问来源于stack exchange,提问作者Roger Hill

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 00:47:29