Здравствуйте. Дело происходит в VS2005 (C#). В некотором классе:
public delegate void UInt64Delegate1(UInt64 num);
public delegate void UInt64Delegate2(UInt64 num);
public event UInt64Delegate1 UInt64Event;
Затем в методе класса пишем одно из:
UInt64Event += new UInt64Delegate1(UInt64Method);//OK
UInt64Event += new UInt64Delegate2(UInt64Method);//Compile-time error:Operator '+=' cannot be applied to operands of type 'FramesTest.Form1.UInt64Delegate1' and 'FramesTest.Form1.UInt64Delegate2'
UInt64Event += (UInt64Delegate1)(new UInt64Delegate2(UInt64Method));//Compile-time error:Cannot convert type 'FramesTest.Form1.UInt64Delegate2' to 'FramesTest.Form1.UInt64Delegate1'
UInt64Event += (UInt64Delegate1)(System.Delegate)(new UInt64Delegate2(UInt64Method)); //Run-time error: InvalidCastException: Unable to cast object of type 'UInt64Delegate2' to type 'UInt64Delegate1'.
Вопрос: почему, казалось бы, очевидно-идентичные типы данных делегатов не преобразуются друг в друга?
Здравствуйте, AkaSaint, Вы писали:
AS>Вопрос: почему, казалось бы, очевидно-идентичные типы данных делегатов не преобразуются друг в друга?
Давайте разберемся сначала вот с таким кодом, казалось бы, никак не связанным с вашими делегатами:
class A
{
int i;
}
class B
{
int i;
}
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.ControlAppDomain)]
static void Main(string[] args)
{
A a;
a = new A(); //OK
a = (A)new B(); //Compile-time error:Cannot convert type 'B' to 'A'
a = (A)(object)new B(); //Run-time error: InvalidCastException: Unable to cast object of type 'B' to type 'A'
}
Здравствуйте, AkaSaint, Вы писали:
AS>Вопрос: почему, казалось бы, очевидно-идентичные типы данных делегатов не преобразуются друг в друга?
Потому что типы это разные даже несмотря на совпадение сигнатур.
Преобразование типов делегатов
От:
Аноним
Дата:
25.04.06 10:34
Оценка:
Другими словами надо понимать что делегат — это на самом деле класс!!!!
Так должно быть более понятно!
Да, теперь понятно! Я, с одной стороны, имел неосторожность забыть в этом вопросе, что делегат — это класс; с другой, меня сбило с панталыку явное упоминание в MSDN о том, что любой тип делегата можно привести к System.Delegate и обратно — я решил, что, раз это написано явно, то имеется в виду некий особый, свойственный именно делегатам, механизм приведения типов, который позволит привести делегат одного типа к делегату другого, но идентичного по сигнатуре типа.
Теперь вопрос: а есть ли способ все-таки выполннить такое приведение? Имеет место быть большое нежелание вызывать методы, на которые указывает делегат, через Invoke.
Здравствуйте, AkaSaint, Вы писали:
AS>Теперь вопрос: а есть ли способ все-таки выполннить такое приведение? Имеет место быть большое нежелание вызывать методы, на которые указывает делегат, через Invoke.
Можно создать новый делегат на основе метода Invoke старого делегата.
using System;
delegate void F1(int a, string b);
delegate void F2(int a, string b);
class Program
{
public static void Main()
{
F1 f1 = Foo;
F2 f2 = Convert(f1);
f2(57, "test");
}
static F2 Convert(F1 f1)
{
return f1.Invoke;
}
static void Foo(int a, string b)
{
Console.WriteLine("a = {0}, b = {1}", a, b);
}
}
Здравствуйте, Mab, Вы писали:
Mab>Можно создать новый делегат на основе метода Invoke старого делегата.
Или короче
using System;
delegate void F1(int a, string b);
delegate void F2(int a, string b);
class Program
{
public static void Main()
{
new F2(new F1(Foo))(57, "test");
}
static void Foo(int a, string b)
{
Console.WriteLine("a = {0}, b = {1}", a, b);
}
}
Здравствуйте, AkaSaint, Вы писали:
AS>Теперь вопрос: а есть ли способ все-таки выполннить такое приведение? Приведение делегата одного типа к делегату другого типа (пусть даже они и имеют одинаковые сигнатуры) невозможно так же как и невозможно примедение типа A к типу B из разных веток наследования.
AS>Имеет место быть большое нежелание вызывать методы, на которые указывает делегат, через Invoke.
А в .NET подругому не получится — только через Invoke. Указатель на функцию, запакованную в экземпляре делегата, хранится где-то в структуре System.Delegate (и хорошо, что к нему нет доступа).
Тебе наверное хочется сложить все экземпляры делегатов с одинаковой сигнатурой в цепочку и потом вызвать их все разом (одним Invoke'ом). Обратно контроль типов! В одной цепочке все делегаты должны быть одного типа. Кругом засада
НО! Если заметить, что все экземпляры делегатов с одинаковой сигнатурой но разных типов имеют метод Invoke с этой же сигнатурой, то можно построить цепочку из этих Invoke'ов, завернутых в экземпляры делегатов одного типа.
Здравствуйте, ie, Вы писали:
ie>Здравствуйте, AkaSaint, Вы писали:
AS>>Вопрос: почему, казалось бы, очевидно-идентичные типы данных делегатов не преобразуются друг в друга?
ie>Давайте разберемся сначала вот с таким кодом, казалось бы, никак не связанным с вашими делегатами:
ie>
ie>class A
ie>{
ie> int i;
ie>}
ie>class B
ie>{
ie> int i;
ie>}
ie>[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.ControlAppDomain)]
ie>static void Main(string[] args)
ie>{
ie> A a;
ie> a = new A(); //OK
ie> a = (A)new B(); //Compile-time error:Cannot convert type 'B' to 'A'
ie> a = (A)(object)new B(); //Run-time error: InvalidCastException: Unable to cast object of type 'B' to type 'A'
ie>}
ie>
ie>Где проблема в этом коде вы понимаете?
я не понимаю. У меня скорее всего проблема похожего сорта. Получаю исключение InvalidCastException Unable to cast 'Type1' to 'Type1'. Type1 (условно) это делегат полученный вызовом Marshal.GetDelegateForFunctionPointer, при этом исходный указатель берется через WinApi. А потом при попытке Type1 type1 = (Type1) Marshal.GetDelegateForFunctionPointer(intPtr, typeof(Type1)) исключение. Если не кастировать, то исключений нет.