Search code examples
c#portable-class-library

Why can't I call Delegate.CreateDelegate in my Portable Class Library?


I have the following problem: I want to call Delegate.CreateDelegate from within my Portable Class Library targeting .NET 4.5, Windows Phone 8 and Windows 8 Store Apps, but my code does not compile. The compiler says that it cannot find the method on the Delegate type.

The funny thing is that e.g. the PRISM library by Microsoft can call 'Delegate.CreateDelegate' from a Portable Class Library. It does so in the DelegateReference class. The PRISM portable class library targets .NET 4.0, Windows 8 Store Apps, Windows Phone 8 and Silverlight 5 (and thusly an even more restrictive set).

The code that does not compile looks like this:

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);

An example can be downloaded here: https://dl.dropboxusercontent.com/u/14810011/PortableClassLibraryReferenceProblem.zip

It contains my library project and a very stripped version of the PRISM PubSubEvents project containing only the DelegateReference class and its interface. The complete source code of the latter can be found here: http://prismwindowsruntime.codeplex.com/SourceControl/latest

What can I do to use all Delegate members? Thank you in advance for your help!

EDIT after Henk Holterman's answer:

GetMethodInfo() is an extension method that is supported by the PCL subset. Anyway, that is not related to the problem that I cannot call Delegate.CreateDelegate while PRISM's PCL project can.

Picture of code that does not compile

EDIT 2 after Hans Passants comment:

I just played around and found out that when I activate Silverlight 5 as a target of the portable library then Delegate.CreateDelegate is indeed accessible (and the GetMethodInfo Extension Method no longer is). Is Delegate.CreateDelegate then maybe mapped to another API for Windows 8 Store and Phone apps internally? It's the only way I could think of how this method would be suddenly accessible just because I added Silverlight 5 as a valid target.

(You can reproduce this by right-clicking on the "MyPortableClassLibrary" project, click "Properties" and in the "Library" tab click change to select the frameworks that are targeted by the portable library.)

Also, earlier today, I created an Windows Store App project and saw that there was no CreateDelegate method defined on the Delegate class in .NET for Windows Runtime.

In my actual project, I do not want to target Silverlight 5 as I use IObservable<T> and IObserver<T> heavily using Rx and these interfaces are not defined in Silverlight.


Solution

  • What you are seeing when you add/remove Silverlight, is portable flipping between two different .NET API surface areas. I cover these two different surface areas here: What is .NET Portable Subset (Legacy)?.

    In what we call the legacy surface area, this method lives on Delegate. In the new surface area, this method has been moved to MethodInfo.

    Why did we do this?

    For layering reasons. In the new surface, reflection types (ie Assembly, MemberInfo, MethodInfo, etc) are considered as living in a higher layer than the core primitives, which includes Delegate. Unlike the legacy surface area (where they all live in mscorlib), these types in different assemblies; System.Reflection.dll and System.Runtime.dll, respectively.

    This method (a few others) were causing something at a lower layer (System.Runtime.dll) to depend on something at a higher layer (System.Reflection.dll). To prevent that, the dependency was reversed.