10

我有以下问题:我想Delegate.CreateDelegate从面向 .NET 4.5、Windows Phone 8 和 Windows 8 应用商店应用程序的便携式类库中调用,但我的代码无法编译。编译器说它找不到该Delegate类型的方法。

有趣的是,例如 Microsoft 的 PRISM 库可以从可移植类库中调用“Delegate.CreateDelegate”。它在DelegateReference课堂上这样做。PRISM 可移植类库面向 .NET 4.0、Windows 8 应用商店应用、Windows Phone 8 和 Silverlight 5(因此限制性更强)。

未编译的代码如下所示:

public class MyClass
{
    public void MyMethod<T>(EventHandler handler)
    {
        var @delegate = Delegate.CreateDelegate(typeof (OpenEventHandler<T>), null, handler.GetMethodInfo());
    }
}

public delegate void OpenEventHandler<in T>(T target, object sender, EventArgs arguments);

可以在此处下载示例:https ://dl.dropboxusercontent.com/u/14810011/PortableClassLibraryReferenceProblem.zip

它包含我的库项目和一个非常精简的 PRISM PubSubEvents 项目版本,仅包含DelegateReference类及其接口。后者的完整源代码可以在这里找到:http: //prismwindowsruntime.codeplex.com/SourceControl/latest

我该怎么做才能使用所有Delegate成员?预先感谢您的帮助!

在 Henk Holterman 回答后编辑:

GetMethodInfo() 是 PCL 子集支持的扩展方法。无论如何,这与我不能调用Delegate.CreateDelegate而 PRISM 的 PCL 项目可以调用的问题无关。

无法编译的代码图片

Hans Passants 评论后的编辑 2 :

我只是玩了一下,发现当我激活 Silverlight 5 作为可移植库的目标时,Delegate.CreateDelegate确实可以访问(并且 GetMethodInfo 扩展方法不再是)。那么可能会在Delegate.CreateDelegate内部映射到 Windows 8 Store 和 Phone 应用程序的另一个 API?这是我能想到的唯一方法,因为我将 Silverlight 5 添加为有效目标,所以突然可以访问此方法。

(您可以通过右键单击“MyPortableClassLibrary”项目来重现此内容,单击“Properties”并在“Library”选项卡中单击更改以选择可移植库所针对的框架。)

另外,今天早些时候,我创建了一个 Windows Store App 项目,发现.NET 中CreateDelegate的类上没有为 Windows 运行时定义方法。Delegate

在我的实际项目中,我不想在使用IObservable<T>IObserver<T>大量使用 Rx 时以 Silverlight 5 为目标,并且这些接口在 Silverlight 中没有定义。

4

2 回答 2

13

好的,睡了一夜之后,我意识到我的问题实际上应该是“如何在 Windows 运行时引入的新 API 中动态创建委托?” . 正如 Rafael 在我的问题的评论中指出的那样,除了 .NET 之外,当 Windows 8 / Phone 8 被定位时,还提供了不同的 API。如果 Silverlight 也是目标,那么 Windows 8 / Phone 8 中不可用的 API 将被映射,这解释了为什么Delegate.CreateDelegate当我将 Silverlight 添加为可移植类库的目标时我可以突然调用。在 .NET 中,新的反射 API 是在 .NET 4.5 中引入的。

无论如何,要在 Windows 8 / Windows Phone 8 中创建委托,必须使用该MethodInfo.CreateDelegate方法,就像这样:

public class MyClass
{
    public void MyMethod<T>(EventHandler handler)
    {
        var methodInfo = handler.GetMethodInfo();
        var @delegate = methodInfo.CreateDelegate(typeof(OpenEventHandler<T>), null);
    }
}

public delegate void OpenEventHandler<in T>(T target, object sender, EventArgs arguments);
于 2013-08-12T10:49:28.850 回答
10

添加/删除 Silverlight 时您看到的是在两个不同的 .NET API 表面区域之间进行可移植翻转。我在这里介绍这两个不同的领域:什么是 .NET 便携式子集(旧版)?.

在我们所说的遗留表面区域中,这种方法存在于 Delegate 上。在新的表面区域中,此方法已移至 MethodInfo。

我们为什么这样做?

出于分层的原因。在新的表面中,反射类型(即,Assembly、MemberInfo、MethodInfo 等)被认为位于比包括 Delegate 在内的核心原语更高的层中。与传统的表面区域(它们都存在于 mscorlib 中)不同,这些类型位于不同的程序集中;System.Reflection.dll 和 System.Runtime.dll 分别。

这种方法(其他一些方法)导致较低层(System.Runtime.dll)的某些东西依赖于较高层(System.Reflection.dll)的某些东西。为了防止这种情况发生,依赖关系被颠倒了。

于 2013-08-14T20:58:50.693 回答