不幸的是,据我所知,此映射并未在 .NET Framework 内的代码中公开。为此,我之前查看了 .NET Framework 参考源,发现在 .NET 代码中,有很多很长的每种类型的 switch 语句,就像您试图避免的那样,但似乎没有一个要暴露在外面。
如果您真的只是想从 SqlTypes 映射到最喜欢的 .NET 类型,我认为您最好的选择是将映射表 in the MSDN docs 转换为代码。请注意,MSDN 上的表格(至少)有两个错误:#1:没有名为“DateTime2”的 .NET 类型(我使用了 DateTime),也没有名为“Xml”的类型(我使用了 SqlXml)。
无论如何,这是我一直在使用的映射 - 使用字典而不是开关,以便在没有单独方法的情况下轻松访问。
public static Dictionary<SqlDbType, Type> TypeMap = new Dictionary<SqlDbType, Type>
{
{ SqlDbType.BigInt, typeof(Int64) },
{ SqlDbType.Binary, typeof(Byte[]) },
{ SqlDbType.Bit, typeof(Boolean) },
{ SqlDbType.Char, typeof(String) },
{ SqlDbType.Date, typeof(DateTime) },
{ SqlDbType.DateTime, typeof(DateTime) },
{ SqlDbType.DateTime2, typeof(DateTime) },
{ SqlDbType.DateTimeOffset, typeof(DateTimeOffset) },
{ SqlDbType.Decimal, typeof(Decimal) },
{ SqlDbType.Float, typeof(Double) },
{ SqlDbType.Int, typeof(Int32) },
{ SqlDbType.Money, typeof(Decimal) },
{ SqlDbType.NChar, typeof(String) },
{ SqlDbType.NText, typeof(String) },
{ SqlDbType.NVarChar, typeof(String) },
{ SqlDbType.Real, typeof(Single) },
{ SqlDbType.SmallInt, typeof(Int16) },
{ SqlDbType.SmallMoney, typeof(Decimal) },
{ SqlDbType.Structured, typeof(Object) }, // might not be best mapping...
{ SqlDbType.Text, typeof(String) },
{ SqlDbType.Time, typeof(TimeSpan) },
{ SqlDbType.Timestamp, typeof(Byte[]) },
{ SqlDbType.TinyInt, typeof(Byte) },
{ SqlDbType.Udt, typeof(Object) }, // might not be best mapping...
{ SqlDbType.UniqueIdentifier, typeof(Guid) },
{ SqlDbType.VarBinary, typeof(Byte[]) },
{ SqlDbType.VarChar, typeof(String) },
{ SqlDbType.Variant, typeof(Object) },
{ SqlDbType.Xml, typeof(SqlXml) },
};
请注意,您需要注意的一件事是大小/精度——某些 SQL 类型(例如 varchar)有大小限制,而 .NET 类型(例如 string)则没有。所以能够知道最可能的 .NET 类型是不够的......如果你使用它来驱动验证规则,你还需要能够防止用户输入无效(例如太大) 通过了解更多关于参数(如精度)的值。请注意,如果您查看 SqlClient 源代码,它们会使用特殊代码来处理情况,例如根据相应的 SQL 精度设置 Decimal 类型的精度。
请注意,如果您需要 .NET 类型的唯一原因是能够将数据填充到存储的 proc 参数中,您可能想尝试简单地对所有 .NET 值使用 ToString(),将字符串填充到SqlParameter 的 Value 属性,并查看框架是否会为您进行转换/解析。例如,对于 XML 或 Date 参数,您可能可以通过发送字符串来逃避。
此外,由于有一个已知(且很小)的类型列表,您可以通过为每个类型使用强类型解析代码来获得更好的性能,而不是使用反射来查找每种类型的 Parse() 方法,例如代码以下。 (请注意,几种类型(例如 SqlDbType.Udt)不一定具有明显的解析器方法——您需要弄清楚您想要如何处理这些。)
public static Dictionary<SqlDbType, Func<string, object>> TypeMapper = new Dictionary<SqlDbType, Func<string, object>>
{
{ SqlDbType.BigInt, s => Int64.Parse(s)},
{ SqlDbType.Binary, s => null }, // TODO: what parser?
{ SqlDbType.Bit, s => Boolean.Parse(s) },
{ SqlDbType.Char, s => s },
{ SqlDbType.Date, s => DateTime.Parse(s) },
{ SqlDbType.DateTime, s => DateTime.Parse(s) },
{ SqlDbType.DateTime2, s => DateTime.Parse(s) },
{ SqlDbType.DateTimeOffset, s => DateTimeOffset.Parse(s) },
{ SqlDbType.Decimal, s => Decimal.Parse(s) },
{ SqlDbType.Float, s => Double.Parse(s) },
{ SqlDbType.Int, s => Int32.Parse(s) },
{ SqlDbType.Money, s => Decimal.Parse(s) },
{ SqlDbType.NChar, s => s },
{ SqlDbType.NText, s => s },
{ SqlDbType.NVarChar, s => s },
{ SqlDbType.Real, s => Single.Parse(s) },
{ SqlDbType.SmallInt, s => Int16.Parse(s) },
{ SqlDbType.SmallMoney, s => Decimal.Parse(s) },
{ SqlDbType.Structured, s => null }, // TODO: what parser?
{ SqlDbType.Text, s => s },
{ SqlDbType.Time, s => TimeSpan.Parse(s) },
{ SqlDbType.Timestamp, s => null }, // TODO: what parser?
{ SqlDbType.TinyInt, s => Byte.Parse(s) },
{ SqlDbType.Udt, s => null }, // consider exception instead
{ SqlDbType.UniqueIdentifier, s => new Guid(s) },
{ SqlDbType.VarBinary, s => null }, // TODO: what parser?
{ SqlDbType.VarChar, s => s },
{ SqlDbType.Variant, s => null }, // TODO: what parser?
{ SqlDbType.Xml, s => s },
};
上面使用的代码很简单,例如:
string valueToSet = "1234";
SqlParameter p = new SqlParameter();
p.SqlDbType = System.Data.SqlDbType.Int;
p.Value = TypeMapper[p.SqlDbType](valueToSet);