ExtensionMethod特定于类,属性或方法

时间:2013-06-06 12:29:26

标签: c# extension-methods

我更喜欢使用很多扩展方法,如ToFloatToIntToLoongToGuidToSqlParameter

现在,因为我一直在我现在的位置工作,所以有些人一直在抱怨他们在每天的物体上看到的大量扩展方法。

对于我的问题,我将起诉这个例子:“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甚至{{1}上使用我无能为力。

现在我的问题是,是否可以创建扩展方法,以便只有在应用于objects时才能使用

喜欢:

List<SqlParameter>

这可能吗?

3 个答案:

答案 0 :(得分:4)

不,这是不可能的。

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

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

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

  1. 可以调用它们的类型,这不是一个选项,因为您需要object
  2. 按名称空间,以及明确添加using X;指令以使其可用的位置。
  3. 另一方面,如果所有对象都可以简单地包装在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");
    }
    

答案 1 :(得分:3)

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

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

另一个选择是扩展列表本身 - 即using或类似。

答案 2 :(得分:2)

不,这是不可能的,但是一个可能的解决方案是namespace你的扩展方法,以至于那些利用它们的人会为那些有意义的语句添加using语句。 p>

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