【问题标题】:What is the C# equivalent to VB.NET's CType Function for use with generic types?与泛型类型一起使用的与 VB.NET 的 CType 函数等效的 C# 是什么?
【发布时间】:2014-10-01 22:42:17
【问题描述】:

假设我在名为 MyDB 的 SQL Server 数据库中有一个名为 MyTable 的表,其中包含以下三个记录:

|ID|MyVarcharColumn|
--------------------
|1|123|
|2|2014-10-01 9:58 AM|
|3|True|

现在假设我有以下 VB.NET 代码:

Public Shared Sub Test()
    Dim myIntValue As Integer = GetValue(Of Integer)(1)
    Dim myDateValue As Date = GetValue(Of Date)(2)
    Dim myBooleanValue As Boolean = GetValue(Of Boolean)(3)
End Sub

Public Shared Function GetValue(Of T)(ByVal id As Integer) As T
    Dim ds As System.Data.DataSet = GetSQLDataSet(String.Format("SELECT MyVarcharColumn FROM MyTable WHERE ID={0}", id))
    Return CType(ds.Tables(0).Rows(0).Item("MyVarcharColumn"), T)
End Function

Public Shared Function GetSQLDataSet(ByVal ForQuery As String) As DataSet
    GetSQLDataSet = New DataSet()
    Dim conn As New System.Data.SqlClient.SqlConnection("Data Source=MyDBServer;Initial Catalog=MyDB;Integrated Security=True")
    Dim cmd As New System.Data.SqlClient.SqlCommand(ForQuery, conn)
    conn.Open()
    Dim da As New System.Data.SqlClient.SqlDataAdapter(cmd)
    da.Fill(GetSQLDataSet)
    conn.Close()
End Function

我可以致电Test(),一切正常。值得注意的是,使用 VB.NET 的CType 函数以某种方式成功地将转换(不是转换,因为底层数据库列值是字符串)转换为正确的类型。

现在,如果我相信 Correct C# conversion counterpart for VB's CTYPE() 和 How do I translate VB.Net's CType() to C# 之类的东西,我应该可以使用以下 C# 代码:

static void Main(string[] args)
{
    int myIntValue = GetValue<int>(1);
    DateTime myDateValue = GetValue<DateTime>(2);
    bool myBooleanValue = GetValue<bool>(3);
}

static T GetValue<T>(int id)
{
    System.Data.DataSet ds = GetSQLDataSet(String.Format("SELECT MyVarcharColumn FROM MyTable WHERE ID={0}", id));
    return (T)ds.Tables[0].Rows[0]["MyVarcharColumn"];
}

public static System.Data.DataSet GetSQLDataSet(string forQuery)
{
    System.Data.DataSet ret = new System.Data.DataSet();
    System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection("Data Source=MyDBServer;Initial Catalog=MyDB;Integrated Security=True");
    System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand(forQuery, conn);
    System.Data.SqlClient.SqlDataAdapter da = new System.Data.SqlClient.SqlDataAdapter(cmd);
    conn.Open();
    da.Fill(ret);
    conn.Close();
    return ret;
}

但是,我在运行时遇到错误,在 return (T)ds.Tables[0].Rows[0]["MyVarcharColumn"]; 上失败,说“指定的转换无效”。

我知道我没有强制转换,因为返回类型是字符串,所以我真正需要的是转换。在 VB.NET 中,CType 函数可以同时扮演这两个角色;但是,在 C# 中,我似乎无法使用像 Convert.ToInt32() 这样的显式类型转换函数之一。由于我在这里处理的是泛型类型,所以这是行不通的。

我想如果我可以把它归结为一个问题,那就是:在 C# 中,我如何将字符串转换为像 VB.NET 的 CType 那样的泛型类型?

【问题讨论】:

    标签: c# vb.net generics casting type-conversion


    【解决方案1】:

    如果您仅需要支持一组非常特定的类型,而它所支持的类型,那么Convert.ChangeType 可能没问题:

    object value = (string) ds.Tables[0].Rows[0]["MyVarcharColumn"];
    return (T) Convert.ChangeType(value, typeof(T));
    

    您可能还需要考虑指定格式提供程序。我会强烈鼓励您避免使用这种代码。例如,您期望 double 值的表示形式是什么? DateTime 呢?理想情况下,您会将这些存储在 SQL 的不同列中,这样您就可以避免自己进行任何转换 - 但如果您必须使用字符串,我可能会非常明确地说明格式化和解析,例如对DateTime 值使用 ISO-8601 格式。您当前的方法使其非常容易受到文化问题的影响。

    我还强烈建议您停止动态构建 SQL。即使对于整数,它也不理想,因为您没有指定格式提供程序,但在所有情况下使用参数化 SQL 只是一个好习惯。

    【讨论】:

    • 谢谢乔恩。我只有一组非常具体的受支持类型,目前不包括双打。不过,这显然是一项正在进行的工作,如果它的范围扩大,重构的时机已经成熟。我知道在许多情况下这种方法是脆弱的,但我在这里没有问题。而且,我知道我将获得关于参数化 SQL 的讲座 :) 我正在懒惰地为帖子构建示例代码,并认为我可以因为整数而侥幸逃脱(即没有 SQL 注入的风险)。跨度>
    • @roryap:“没有 SQL 注入的风险”这取决于您是否有不正当的用户:codeblog.jonskeet.uk/2014/08/08/the-bobbytables-culture。即使double 不是问题,DateTime 也可能会给您带来巨大的问题。如果您在 IMO 的任何地方都使用 ISO-8601 格式会更清晰。
    猜你喜欢
    • 1970-01-01
    • 2011-05-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-12
    • 1970-01-01
    • 1970-01-01
    • 2010-11-09
    相关资源
    最近更新 更多