有的可以直接用“lambda 表达式”作为委托参数,但有的却不行,为什么呢?

imfang 2014-12-03 04:12:00
前两个例子是可以的,但后一个例子就不行,大家看看是为什么,谢谢!!!

static void Main(string[] args)
{
int[] a = { 8, 2, 6, 56, 46, 18 };
Func<int, bool> d = i => i > 18; //Func委托,返回所给整数参数的值是否大于18
bool b = a.Any(d);//数组中有大于18的数据吗?
Console.WriteLine(b);
}

可简写成:
static void Main(string[] args)
{
int[] a = { 8, 2, 6, 56, 46, 18 };
bool b = a.Any(i => i > 18); // Any是个“扩展方法”
Console.WriteLine(b);
}

下面是Func委托的定义
public delegate TResult Func<in T, out TResult>(T arg);


再比如:
class Program
{
static void Main(string[] args)
{
ThreadStart ts=new ThreadStart(Run);
Thread t = new Thread(ts);
t.Start();
}

static void Run()
{
for (int i = 0; i < 1000; ++i)
{
Console.WriteLine(i);
}
}
}

我也可以简写成:

static void Main(string[] args)
{
Thread t = new Thread(() =>
{
for (int i = 0; i < 1000; ++i)
{
Console.WriteLine(i);
}
});
t.Start();
}

这是ThreadStart委托的定义
public delegate void ThreadStart();

都可以直接用“lambda 表达式”作为委托参数,但下面的却不行:
在多线程中更新用户界面时,需要调用Invoke方法来更新用户界面,比如:
public partial class Form1 : Form
{
private delegate void UpdateUIDelegate(int i);
public Form1()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
Thread t=new Thread(doWorker);
t.Start();
}

private void UpdateUI(int i)
{
label1.Text = i.ToString();
}

private void doWorker()
{
UpdateUIDelegate ui = UpdateUI;
for (int i = 0; i < 1000; ++i)
{
label1.Invoke(ui, i);
Thread.Sleep(10);
}
}
}


我想简写成下面的样子:
public partial class Form1 : Form
{
private delegate void UpdateUIDelegate(int i);
public Form1()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
Thread t=new Thread(doWorker);
t.Start();
}

//private void UpdateUI(int i)
//{
// label1.Text = i.ToString();
//}

private void doWorker()
{
for (int i = 0; i < 1000; ++i)
{
label1.Invoke(n => { label1.Text = n.ToString(); }, i); //***出现错误***
Thread.Sleep(10);
}
}
}


却出现错误错误:
无法将 lambda 表达式 转换为类型“System.Delegate”,因为它不是委托类型
但若写成下面的,就没问题了:
label1.Invoke((UpdateUIDelegate)(n => { label1.Text = n.ToString(); }), i);

Invoke的参数如下:
public object Invoke(Delegate method, params object[] args);

和前面不同的是这里的参数是Delegate

我查阅了一些资料,说delegate定义的委托派生自MulticastDelegate,而MulticastDelegate又派生自Delegate,Delegate又派生自object.

我们都知道:
object obj=25;//不需要强制类型转换
int i=(int)object;//需要强制类型转换

Invoke的参数是Delegate,是其他委托的基类,为何这里还需要强制类型转换呢?


...全文
404 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
Forty2 2014-12-04
  • 打赏
  • 举报
回复
引用 2 楼 github_22161131 的回复:
... 一般调用Invoke都是 .Invoke(new Action(() => ...)); 这样用Action这个具体的委托来封装lambda。
也可以用强制转换,让编译器有机会推导出具体类型。 label1.Invoke((Action<int>)(n => { label1.Text = n.ToString(); }), i);
winnowc 2014-12-03
  • 打赏
  • 举报
回复
因为 Delegate 和 MulticastDelegate 本身都是 abstract 的,实际使用时必须有一个具体的委托继承自它们才能new。前两个例子里面方法的参数都是具体的委托类型,所以编译器可以支持自动new那个类型的委托,就能够直接写lambda。而Invoke要求的参数是 Delegate,你给lambda编译器没法知道要转换成哪一个具体类型的委托,就没法自动帮忙new了,所以必须自己指定好具体的委托类型。一般调用Invoke都是 .Invoke(new Action(() => ...)); 这样用Action这个具体的委托来封装lambda。
欢乐的小猪 2014-12-03
  • 打赏
  • 举报
回复
label1.Invoke(n => { label1.Text = n.ToString(); }, i); //***出现错误*** 这里要求无参的 改为label1.Invoke(()=>{});应该没错

110,536

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧