Threadsafe通用扩展方法用法语法问题

时间:2009-07-03 13:40:51

标签: c# multithreading generics user-interface extension-methods

这是我在控件上调用的扩展方法:

public static void Invoke<T>(this T c, Action<System.Windows.Forms.Control> DoWhat)
    where T:System.Windows.Forms.Control
{
    if (c.InvokeRequired)
        c.Invoke(o=> DoWhat(c) );
    else
        DoWhat(c);
}

ds是强类型数据集。 这有效:

Action<DataGridView> a = row => row.DataSource = ds.bLog;
this.dataGridView1.Invoke(a);

这不编译:

this.dataGridView1.Invoke<DataGridView>(o => o.DataSource = ds.bLog);

并说System.Windows.Forms.Control不包含'DataSource'的定义......

我真的要把它分成两行吗? 为了清楚/安全,我应该调用通用扩展方法InvokeSafe吗?

编辑:修改了扩展方法(有效,但我想删除指定的委托要求):

private delegate void myDel();

public static void InvokeSafe<T>(this T c, Action<T> DoWhat) where T : Control
{
    myDel d = delegate() { DoWhat(c); };
    if (c.InvokeRequired)
        c.Invoke(d);
    else
        DoWhat(c);
}

我似乎无法弄清楚如何将myDel分解成块中的匿名委托?

4 个答案:

答案 0 :(得分:4)

问题是您的行为仅在Control中声明(在方法中)。将其更改为:

public static void Invoke<T>(this T c, Action<T> DoWhat)
    where T:System.Windows.Forms.Control
{
    if (c.InvokeRequired)
        c.Invoke((EventHandler) delegate { DoWhat(c) } );
    else
        DoWhat(c);
}

这样编译器就会推断你想要一个Action<DataGridView>,这样调用者中的lambda表达式就可以使用DataSource

答案 1 :(得分:2)

尝试将方法签名更改为:

public static void Invoke<T>(this T c, Action<T> DoWhat)

这会让您的Action使用您指定的所需类型。

答案 2 :(得分:0)

为了进一步说明Jon Said,数据源不在System.Windows.Forms.Control上。数据源位于datagrid上。因此,如果您查看错误消息,您将看到它正在尝试在没有数据源的类型上设置数据源。做Jon建议应该解决问题。

答案 3 :(得分:0)

作品!

public static void InvokeSafe<T>(this T c, Action<T> DoWhat)
where T : System.Windows.Forms.Control
    {

        Action d = delegate() { DoWhat(c); };
        if (c.InvokeRequired)
            c.Invoke(d);
        else
            DoWhat(c);

    }

此代码确实导致InvalidOperationException-跨线程操作无效:

List<customer> c=new List<customer>{new customer{ Name="test"},new customer{Name=   "John doe"}};
        Thread t = new Thread(o => this.dataGridView1.DataSource = c);
        t.Start();

新的扩展方法没有!

List<customer> c=new List<customer>{new customer{ Name="test"},new customer{Name=   "John doe"}};
        Thread t = new Thread(o => this.dataGridView1.InvokeSafe(p => p.DataSource = c));
        t.Start();