CLR定义的方法如 .BeginInvokelogging在哪里?
[编辑,完全改编:]似乎我的问题确实措辞不好,而且也不好受。 所以我希望这个完整的改写帮助…
MSDN告诉清楚指定: Control.BeginInvoke()在创build控件句柄的线程上执行委托,通常这将是GUI线程。 Dispatcher.BeginInvoke()将在创buildDispatcher对象的线程上运行。 这将是我创build的任何线程。
但是对于委托, “ CLR自动定义 BeginInvoke和EndInvoke”,而这些调用在ThreadPool-thread上运行。 除了这个有点令人惊讶的不同的行为,我不知道如何find自动实现的所有function的规格。
例如:Intelli-sense显示我的委托具有DynamicInvoke()。 类System.Delegate {}确实有一个DynamicInvoke()这可能意味着我的代理inheritance它。 但委托{}没有BeginInvoke()。 而Delegate {}有几个我的委托没有的function。 另外我的委托获取GetObjectData()方法。 这似乎来自可分离的。
所以总而言之,出现一个委托从(1)CLR“自动”获取它的方法,(2)委托的一些子集可能MulticastDelegate {},可能(3)ISerializble。 我在哪里可以find委托人获得的所有方法的全面规范? 特别有趣的是BeginInvoke(),它是确切的签名,因为上述两个具有该名称的方法具有不同的签名集合。
[有人在编辑中build议“代表”是“代表”。 我敢说,不是。]
谢谢
Control.Begin / End / Invoke()和Dispatcher.Begin / End / Invoke()方法与委托的Begin / End / Invoke()方法具有相同的名称和相似的行为,但最好放弃是相同的。 最重要的区别在于委托的方法是types安全的 ,而Control和Dispatcher版本则完全没有。 运行时行为也是非常不同的。
pipe理委托的规则在CLI规范ECMA 335的第II.14.6章中详细说明。 最好是阅读这一章,我只是给大纲。
委托声明转换为inheritance自MulticastDelegate的类(不是CLI规范中指定的委托)。 该类总是有4个成员,它们的运行时实现由CLR提供:
-
一个构造函数,它接受一个对象和一个IntPtr。 对象是Delegate.Target,IntPtr是目标方法Delegate.Method的地址。 这些成员稍后在调用委托时使用,如果委托绑定到的方法是实例方法,则Target属性提供此引用,对于静态方法,则为null。 Method属性确定调用哪个方法。 您不直接指定这些参数,编译器会在您使用new运算符或使用+ =运算符预订事件处理程序时提供这些参数。 在事件情况下有了大量的语法糖,你不必明确地使用新的操作符。
-
一个Invoke()方法。 该方法的参数是dynamic生成的,并匹配委托声明。 调用Invoke()方法在同一个线程( 同步调用)上运行委托目标方法。 你很less在C#中使用它,你只需要使用语法sugar,通过使用对象名称和括号来调用委托对象。
-
一个BeginInvoke()方法提供了一种进行asynchronous调用的方法。 当目标方法忙于执行时,该方法很快完成,与ThreadPool.QueueUserWorkItem类似,但具有types安全参数。 返回types始终是System.IAsyncResult,用于查明asynchronous调用何时完成并提供给EndInvoke()方法。 第一个参数是一个可选的System.AsyncCallback委托对象,当asynchronous调用完成时,它的目标会被自动调用。 第二个参数是一个可选的对象 ,它将按原样传递给callback函数,有助于跟踪状态。 其他参数是dynamic生成的,并与委托声明相匹配。
-
一个EndInvoke()方法。 它需要IAsyncResulttypes的单个参数,您必须通过从BeginInvoke()获得的那个参数。 它完成asynchronous调用并释放资源。
您在代理对象上看到的任何其他方法都是从基类MulticastDelegate和Delegateinheritance的方法。 像DynamicInvoke()和GetObjectData()一样。
asynchronous调用是棘手的,你很less需要使用它们。 实际上,它们不可用于.NETCore目标,如Silverlight。 委托目标方法在任意线程池线程上运行,就像Threadpool.QueueUserWorkItem()一样。 它可能抛出的任何未处理的exception都会被捕获并终止该线程,但不会终止该程序。 你必须调用EndInvoke(),不这样做会导致资源泄漏10分钟。 如果目标方法抛出一个exception,那么当你调用EndInvoke()时将会重新产生exception。 您无法控制线程池线程,无法取消或中止它。 Task或Thread类是更好的select。
MSDN是相关的,委托types的方法没有logging。 它假设你知道他们做了什么,他们看起来像从规范和委托声明。
根据你的问题,答案将是这些粗线。 MSDN可能不会更好,但它是好的,但:)
杰弗里·里希特(Jeffrey Richter)写过你在上面的问题中提出的问题。 他在MSDN杂志上有这篇文章。 http://msdn.microsoft.com/en-us/magazine/cc164139.aspx本文将向您展示实际上(可能不是实际但非常接近)的这个BeginInvoke和EndInvoke实际上在;.NET中实现的实现CLR。 投入一些时间在这篇文章之后,我不认为现在你需要提前阅读。 Jeffrey Richter在他的书“CLR Via C#”中也很好地解释了这一点。
大多数UI应用程序是单线程的。 UI上的控件只能使用创build它们的线程访问。
在Winforms中存在这个Control.Invoke。 它会自动在UI线程上调用你的代码。 在WPF世界中,我们没有Control.Invoke。 在WPF中,我们有Dispatcher而不是Control。
现在委托vs委托。 Hans Passant提供了一个非常好的答案。
所以稍微留意一下,我正在写这个答案。
在MSDN上提到的代表是一个类。 让我们拿这个代码(取自msdn http://msdn.microsoft.com/en-us/library/ms173171(v=vs.80).aspx )
public delegate int PerformCalculation(int x, int y);
正如你在这里看到的,我们有一个委托(注意一个小的'D')。 这是一个关键字来定义一个委托或把它放在简单的话,这是一个关键字来定义一个variablesPerformCalculation实际上包含一个方法的引用。
我想你已经意识到这一点,但只是为了完整。
现在使用这个variables,并使用如下代码调用一个方法:
using System; // Declare delegate -- defines required signature: delegate void SampleDelegate(string message); class TestDelegate { private void CallMeUsingDelegate(string m_param) { Console.WriteLine("Called me using parameter - " + m_param); } public static void Main(string[] args) { // Here is the Code that uses the delegate defined above. SampleDelegate sd = new SampleDelegate(CallMeUsingDelegate); sd.Invoke("FromMain"); } }
现在调用一个方法,你需要写一个完整的方法作为上面的CallMeUsingDelegate方法。 C#有这个匿名方法可以用来调用一个方法,而不需要把它写成一个方法。
所以上面的代码也可以写成
使用系统; //声明委托 – 定义所需的签名:委托void SampleDelegate(string message);
class TestDelegate { public static void Main(string[] args) { // Here is the Code that uses the delegate defined above. SampleDelegate sd = delegate(param) { Console.WriteLine("Called me using parameter - " + param); }; sd.Invoke("FromMain"); } }
这与上面的代码做了相同的工作。 但是现在我们需要less写一些代码。 编译器将为上述两个版本创build相同的IL代码。 但在这种情况下,新方法将由编译器自动生成名称。
当涉及到BeginInvoke和EndInvoke时,它们被用来asynchronous调用方法。 这是使用CLR提供的线程池完成的。
基本上会发生什么,你调用一个方法
IAsyncResult ar = sd.BeginInvoke(CallMeUsingDelegate, callMeOnCompletion, sd);
这里Delegate是你正在调用的方法。 会发生什么情况是程序的Thread将调用BeginInvoke方法,该方法将在内部调用CLR ThreadPool线程的Delegate参数中指定的方法。 然后程序继续运行并返回一个实现了IAsyncResult接口的对象。 您可以使用此对象查询使用委托调用的任务的进度(请注意委托sd作为3parameter passing)。
CallMeUsingDelegate方法在一个单独的线程(ThreadPool的)上被调用。 当任务完成时,ThreadPool将调用指定为2参数的Callback方法。
看着这一切,你可能会想,为什么我们需要EndInvoke呢?
那么这是因为如果你不调用EndInvoke,CLR ThreadPool将持有对这个操作的引用,并且你会泄漏一些内存。 因此,在指定的callback方法中调用EndInvoke总是一个好习惯。
我希望这现在清除(不是全部),但一些想法。