Почему я не могу назвать Delegate.CreateDelegate в моей Portable Class Library?
У меня есть следующая проблема: я хочу вызвать Delegate.CreateDelegate
из моей библиотеки Portable Class Library, ориентированной на .NET 4.5, Windows Phone 8 и Windows 8 Store Apps, но мой код не компилируется. Компилятор говорит, что он не может найти метод в типе Delegate
.
Самое забавное, что, например, библиотека PRISM от Microsoft может вызвать "Delegate.CreateDelegate" из портативной библиотеки классов. Он делает это в классе DelegateReference
. Портативная библиотека классов PRISM предназначена для .NET 4.0, Windows 8 Store Apps, 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
? Заранее благодарю вас за помощь!
ИЗМЕНИТЬ после ответа Хенка Холтермана:
GetMethodInfo() - это метод расширения, поддерживаемый подмножеством PCL. Во всяком случае, это не связано с проблемой, которую я не могу назвать Delegate.CreateDelegate
, в то время как проект PRISM PCL может.
![Picture of code that does not compile]()
EDIT 2 после комментария Hans Passants:
Я только что поиграл и узнал, что когда я активирую Silverlight 5 как цель переносимой библиотеки, тогда Delegate.CreateDelegate
действительно доступен (и метод расширения GetMethodInfo больше не существует). Является ли Delegate.CreateDelegate
, а может быть, сопоставлен с другим API для приложений Windows 8 Store и Phone внутри? Это единственный способ, которым я мог бы думать о том, как этот метод будет внезапно доступен только потому, что я добавил Silverlight 5 в качестве действительной цели.
(Вы можете воспроизвести это, щелкнув правой кнопкой мыши по проекту "MyPortableClassLibrary", нажмите "Свойства" и на вкладке "Библиотека" нажмите "Изменить", чтобы выбрать рамки, на которые нацелена переносная библиотека.)
Кроме того, ранее сегодня я создал проект приложения Windows Store и увидел, что не существует метода CreateDelegate
, определенного в классе Delegate
в .NET для Windows Runtime.
В моем фактическом проекте я не хочу указывать Silverlight 5, поскольку я использую IObservable<T>
и IObserver<T>
сильно используя Rx, и эти интерфейсы не определены в Silverlight.
Ответы
Ответ 1
То, что вы видите, когда вы добавляете/удаляете Silverlight, является переносом между двумя различными областями поверхности API. Я описываю эти две области поверхности: Что такое .NET Portable Subset (Legacy)?.
В том, что мы называем унаследованной поверхностью, этот метод работает на делетете.
В новой области поверхности этот метод был перемещен в MethodInfo.
Почему мы это сделали?
Для объяснения причин. На новой поверхности типы отражения (т.е. Assembly, MemberInfo, MethodInfo и т.д.) Рассматриваются как живущие на более высоком уровне, чем основные примитивы, в том числе Делегат. В отличие от старой площади поверхности (где все они живут в mscorlib), эти типы в разных сборках; System.Reflection.dll и System.Runtime.dll соответственно.
Этот метод (несколько других) вызывал что-то на более низком уровне (System.Runtime.dll), чтобы зависеть от чего-то на более высоком уровне (System.Reflection.dll). Чтобы этого избежать, зависимость была отменена.
Ответ 2
ОК, после ночи сна я узнал, что мой вопрос на самом деле должен быть "Как мне динамически создавать делегаты в новом API, представленном с помощью Windows Runtime?" . Как указывал Рафаэль в комментариях к моему вопросу, различные API-интерфейсы предоставляются, когда в Windows 8/Phone 8 используется помимо .NET. Если Silverlight также нацелен, тогда API-интерфейсы, которые недоступны в Windows 8/Phone 8, будут сопоставлены, и это объясняет, почему я могу неожиданно позвонить Delegate.CreateDelegate
, когда я добавлю Silverlight в качестве объекта переносимой библиотеки классов. В .NET новые API для Reflection были представлены с .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);