#c# #generics #delegates
#c# #общие сведения #делегаты
Вопрос:
class Test
{
public delegate void FruitDelegate(Fruit f);
public void Notify<T>(Action<T> del) where T : Fruit
{
FruitDelegate f = del; // Cannot implicitly convert type 'Action<T>' to 'FruitDelegate
}
}
Fruit — это пустой класс. Оба этих делегата имеют одинаковую подпись.
Кажется, я не могу заставить что-либо из этого работать. Может быть, это помогло бы, если бы я объяснил, что я пытаюсь сделать (предоставить некоторый контекст).
Я хочу создать класс, который имеет общий статический метод, который предоставляет тип и обратный вызов метода (как в приведенном выше примере).
Проблема, с которой я сталкиваюсь, заключается в том, что делегат содержит параметр, и я не хочу приводить его в обратном вызове метода. Например, я хочу это:
public void SomeMethod()
{
Test.Notify<Apple>(AppleHandler);
}
private void AppleHandler(Apple apple)
{
}
Вместо этого:
public void SomeMethod()
{
Test.Notify<Apple>(AppleHandler);
}
private void AppleHandler(Fruit fruit)
{
Apple apple = (Apple)fruit;
}
Возможно ли такое?
Ответ №1:
это то, что вы хотите?
static void Main(string[] args)
{
Program p = new Program();
p.SomeMethod();
}
public class Fruit
{ }
public class Apple : Fruit { }
public delegate void FruitDelegate<in T>(T f) where T : Fruit;
class Test
{
public static void Notify<T>(FruitDelegate<T> del)
where T : Fruit, new()
{
T t = new T();
del.DynamicInvoke(t);
}
}
private void AppleHandler(Apple apple)
{
Console.WriteLine(apple.GetType().FullName);
}
public void SomeMethod()
{
FruitDelegate<Apple> del = new FruitDelegate<Apple>(AppleHandler);
Test.Notify<Apple>(del);
}
Комментарии:
1. Вау… Волшебство! Работает отлично. Мне придется некоторое время смотреть на это. Перемещаем это в начало.
Ответ №2:
Есть веская причина, по которой вы не можете этого сделать. Предположим, что остальная часть вашего метода была:
class Test
{
public delegate void FruitDelegate(Fruit f);
public void Notify<T>(Action<T> del) where T : Fruit
{
FruitDelegate f = del;
f(new Banana()); //should be legal, but del may be Action<Apple>
}
}
Это определенно не сработало бы, поэтому компилятор здесь прав.
Ответ №3:
Как насчет чего-то подобного?
public void Notify<T>(Action<T> del) where T : Fruit
{
FruitDelegate f = fruit => del((T)fruit);
}
FruitDelegate
Экземпляр при вызове выдаст исключение InvalidCastException, если, скажем, an AppleHandler
был вызван с Banana
аргументом.