无法将delegate(委托)转换为泛型类型T
为什么我们不能将委托的实例强制转换为通用类型T
?
考虑一个实用程序方法CreateDelegate
,它创建一个T实例,它是一个委托,即从MulticastDelegate
派生的类型。
T CreateDelegate<T>() {… }
不幸的是,泛型不允许将T
约束到从MulticastDelegate
派生的类型,从而产生以下编译错误:
约束不能是特殊类'System.MulticastDelegate'
然而,此实用程序方法检查T
是否与MulticastDelegate
兼容,并通过Delegate::CreateDelegate
反射创建代理。但是,如果我们尝试将Delegate::CreateDelegate
的结果转换为T
,我们将收到以下编译错误:
无法将类型'System.Delegate'转换为'T'
但是,如果我先将其投放到object
然后投放到T
,它会正常工作:
T h = (T) ((object) Delegate.CreateDelegate(typeof(T), target, m));
为什么我们不能直接将代表委托给T?
1 个答案:
答案 0 :(得分:10)
C#语言强制静态检查从类型X到类型Y的强制转换是否有效 - 即它是否使有意义,因为编译器可以(在某种程度上)保证兼容性并拒绝错误在编译时清楚。不受约束的泛型类型T
和System.Delegate
没有任何直接的共同点。但是,当转换为object
时,编译器知道每个类型实际上都是object
,因此它允许转换。这并不意味着在特定情况下运行时类型检查不会失败。
as
运算符更宽松一点,因为它不会导致其他无效转换的异常。编译器在应用静态检查时也不那么严格。在您的特定情况下,这很有用,因为您可以省略object
的中间演员并使用as T
。但是,需要的是as
仅适用于类类型,因此您必须应用where T : class
约束。
所以这个方法看起来像这样(简化):
public T CreateDelegate<T>(…) where T : class
{
return Delegate.CreateDelegate(typeof(T), …) as T;
}
正如@usr建议的那样,推荐读物是Eric Lippert的博客,例如: this article on casts and type parameters
出处:https://www.thinbug.com/q/35321586
=======================================================================================
关于委托:异常{ 无法将 匿名方法 转换为类型“System.Delegate”,因为它不是委托类型 }
异常{ 无法将 匿名方法 转换为类型“System.Delegate”,因为它不是委托类型 }
委托实际上是把方法名作为参数,但是若有好多个方法时,就要指明是哪个参数
查看如下代码:
this.Invoke(delegate
{
MessageBox.Show("t4");
});
熟悉winform的开发者都知道,this是一个窗体的实例,故不做另外解释。该代码的运行,就会导致异常:{ 无法将 匿名方法 转换为类型“System.Delegate”,因为它不是委托类型 }。
其实,要从错误的提示信息来看,这个匿名方法写的是一点问题都没有的。问题的关键是invoke这个函数的参数,我们查看其原型为:
public object Invoke(Delegate method)
也就说,它所接受的是一个Delegate,那么,任何一个派生自Delegate的实例,都是可被接受的。我们知道,类似ThreadStart,MethodInvoker都派生自Delegate,那么编译器在转化这个匿名函数的时候,就不知道要将这个匿名函数转为ThreadStart还是MethodInvoker,于是报错。(代表一个委托函数的,还有ParameterizedThreadStart、WaitCallback、AsyncCallback等,只不过他们都是带有参数的。)
正确的语法应该如下:
this.Invoke(new MethodInvoker(delegate { MessageBox.Show("t3"); }));
或者
this.Invoke((ThreadStart)delegate
{
MessageBox.Show("t4");
});
这样,编译器就知道要将匿名函数转化为哪个参数了。
题外话:注意这里,无论是new还是转型,都是一样的。
现将各类语法总结如下:
private void button1_Click(object sender, EventArgs e)
{
//将delegate转为ThreadStart
Thread t1 = new Thread((ThreadStart)delegate { MessageBox.Show("t1"); });
t1.Start();
//将delegate转为ThreadStart的第二种写法
Thread t2 = new Thread(new ThreadStart(delegate() { MessageBox.Show("t2"); }));
t2.Start();
//将delegate转为MethodInvoker
this.Invoke(new MethodInvoker(delegate { MessageBox.Show("t3"); }));
//将delegate转为ThreadStart
this.Invoke((ThreadStart)delegate
{
MessageBox.Show("t4");
});
//将delegate转为WaitCallback
ThreadPool.QueueUserWorkItem((WaitCallback)delegate
{
MessageBox.Show("t5");
});
//默认将delegate转为WaitCallback,因为QueueUserWorkItem只接受WaitCallback参数
ThreadPool.QueueUserWorkItem(delegate
{
MessageBox.Show("t5");
});
WaitCallback wc = new WaitCallback(this.DoSomethingWithState);
ThreadPool.QueueUserWorkItem(wc, "i am state.");
}
void DoSomethingWithState(Object c)
{
MessageBox.Show("t6" + c.ToString());
}
最后,附上几个Delegate的原型:
public delegate void ThreadStart();
public delegate void MethodInvoker();
public delegate void WaitCallback(object state);
public delegate void ParameterizedThreadStart(object obj);
public delegate void AsyncCallback(IAsyncResult ar);
出处:https://www.cnblogs.com/liulaocai2/p/4383494.html
=======================================================================================
个人总结,判断泛型是否为delegate类型
我们根据自己代码的情况进行判断,主要是依据运算符 is、as 、IsSubclassOf、IsAssignableFrom等,具体的可以看 ( 跳转 ) 我前面的相关文章的介绍。
is和as主要是针对实例运算的,而IsSubclassOf和IsAssignableFrom主要是针对类型运算的。
例如:
private static T GetMethodDelegate<T>() where T : class { T res = default(T); Type delegateType = typeof(T); bool isDelegateType = delegateType is Delegate; var s1 = delegateType.IsAssignableFrom(typeof(Delegate)); var s2 = typeof(Delegate).IsAssignableFrom(delegateType); var s3 = typeof(Delegate).IsSubclassOf(delegateType); var s4 = delegateType.IsSubclassOf(typeof(Delegate)); if (isDelegateType) { DynamicMethod dynamicSpeakWithCall = new DynamicMethod("D", null, new[] { typeof(int) });//res = dynamicSpeakWithCall.CreateDelegate(typeof(T)) as T; } return res; }
关注我】。(●'◡'●)
如果,您希望更容易地发现我的新博客,不妨点击一下绿色通道的【因为,我的写作热情也离不开您的肯定与支持,感谢您的阅读,我是【Jack_孟】!
本文来自博客园,作者:jack_Meng,转载请注明原文链接:https://www.cnblogs.com/mq0036/p/16839788.html
【免责声明】本文来自源于网络,如涉及版权或侵权问题,请及时联系我们,我们将第一时间删除或更改!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
2020-10-29 Vue.js官方中文教程
2020-10-29 vue学习笔记 ---- 系列文章
2020-10-29 基于Asp.net core Kestrel的超迷你http服务器 ---- AServer
2020-10-29 Docker学习—概念及基本应用
2020-10-29 高数 ---- 思维导图(上岸必备)
2018-10-29 DeepLearning.ai学习笔记汇总
2014-10-29 C#格式化字符串