1

我更喜欢使用很多扩展方法,asin ToFloat, ToInt, ToLoong, ToGuid,ToSqlParameter

现在,自从我一直在我现在的位置工作以来,有些人一直在抱怨他们在日常对象上看到的大量扩展方法。

对于我的问题,我将起诉示例:“ToSqlParameter”

    public static SqlParameter ToSqlParameter(this object source, string name, bool structured = false)
    {
        var para = new SqlParameter { ParameterName = name, Value = source };
        if (structured) { para.SqlDbType = SqlDbType.Structured; }
        return para;
    }

目前,每个对象都有可用的扩展方法。

我知道添加类似的东西where T : class只会让它在类上工作,但是因为这个方法应该能够在 , 上使用stringbool甚至objects我也无能为力。

现在我的问题是,是否可以创建扩展方法,以便仅在应用于List<SqlParameter>

像 :

var str = "Some Strnig";
var list = new List<SqlParameter>();
var list2 = new List<string>();
list.Add(str.ToSqlParameter("@str")); //Should work
list2.Add(str.ToSqlParameter("@str")); //Should return 'SqlParameter not found'

这可能吗?

4

3 回答 3

4

不,这是不可能的。

扩展方法仅因您尝试调用它们的类型而被发现,而不是基于周围的上下文。

您有问题的最后一行代码会得到一个不同的错误,因为ToSqlParameter无法将结果添加到列表中,但该方法将可用。

“过滤”扩展方法的唯一方法是:

  1. 它们可以被调用的类型,这里不是一个选项,因为你想要它object
  2. 通过命名空间,因此通过显式添加using X;指令以使其可用的位置。

另一方面,如果所有对象都可以简单地包装在 SqlParameter 中,那么这里有一种不同的方法,使用反射。

这是一个原型(未测试):

public static void AddParameters(this SqlCommand command, object parameters)
{
    foreach (var propertyInfo in parameters.GetType().GetProperties())
    {
        object propertyValue = propertyInfo.GetValue(parameters, null);
        command.Parameters.AddWithValue("@" + propertyInfo.Name, propertyValue);
    }
}

你会像这样使用它:

public void DeletePersonById(int id)
{
    var cmd = new SqlCommand();
    cmd.Connection = ...
    cmd.CommandText = "delete from persons where person_id = @id");
    cmd.AddParameters(new { id });
    cmd.ExecuteNonQuery();
    ...

请注意,此方法仅创建非常基本SqlParameter的对象,您可能希望扩展它以更好地处理特殊类型,例如具有大小的字符串等。

有关我用于简单程序的一些基本代码的更完整示例,请查看此处:Dropbox link to SO16962113.linq。这是一个可以运行的LINQPad程序,它将在本地创建一个 SQL Server 数据库并为查询设置一些虚拟数据。

相关语法(方法在 LINQPad 程序中实现):

using (var conn = new SqlConnection("...").AutoOpen())
{
    // prepare a fresh new database
    conn.Execute("if exists (select * from sysdatabases where name = 'SO16962113') drop database SO16962113");
    conn.Execute("create database SO16962113");
    conn.Execute("use SO16962113");

    // execute some queries
    conn.Execute("create table persons (person_id int primary key not null identity(1,1), person_name varchar(100))");
    conn.Execute("insert into persons (person_name) values ('James'), ('Jon'), ('Mary'), ('Jack')");
    conn.Query<Person>("select * from persons where person_id in (@id1, @id2)", new { id1 = 2, id2 = 4 }).Dump();

    // clean up
    conn.Execute("use master");
    conn.Execute("drop database SO16962113");
}
于 2013-06-06T12:34:20.280 回答
3

不,基本上。解决方案仅基于 的类型str- 在 ( list.Add/ list2.Add) 之外发生的事情与 的解决方案无关ToSqlParameter

我确实必须同意您的同事的意见 -由于对发现的不利影响,扩展object或不受限制通常不是一个好主意。T也许可以将所有这些扩展方法放在一个非常特定的命名空间(Foo.Bar.DbHelpers例如)中,这样它们就不会一直可见(仅当using该命名空间时)。

另一种选择是扩展列表本身- 即this IList<SqlParameter>或类似的。

于 2013-06-06T12:34:38.200 回答
2

不,那是不可能的,但一种可能的解决方案是对namespace您的扩展方法进行如此多的利用,以至于那些利用它们的人会using为那些有意义的语句添加语句。

看,如果我知道我要进行一些转换,但不处理任何SqlParameter对象,那么我只需添加using Extensions.Casting;并且我将拥有一个较小的方法子集。

于 2013-06-06T12:32:50.810 回答