#c# #parameters #delegates #covariance
#c# #параметры #делегаты #ковариация
Вопрос:
Я хочу создать делегат, указывающий на статическую функцию…статическая функция имеет второй параметр типа Flight, класс Flight реализует интерфейс ITravelObject, а второй параметр делегата требует этого интерфейса.
Следующий код не работает. Почему это так? Существует ли какая-либо другая возможная реализация?
namespace CovarianceContravarianceTest
{
public class Data {}
public interface ITravelObject
{
int ID { get; set; }
}
public abstract class BaseObject {}
public class Flight : BaseObject, ITravelObject
{
int ITravelObject.ID {get;set;}
}
public static class LetService
{
public static void DoSomething(Data da, Flight let) {}
}
public delegate void TravelServiceMethodDelegate(Data dataAccess,ITravelObject travelObject);
class Program
{
static void Main(string[] args)
{
TravelServiceMethodDelegate test = new TravelServiceMethodDelegate(LetService.DoSomething);
}
}
}
Это приводит к ошибке
Никакая перегрузка для ‘doSomething’ не соответствует делегату ‘covariancecontravar Variancetest.TravelServiceMethodDelegate’
спасибо всем за ответы, я уже понял, что это даже не проблема ковариации / контравариантности
Комментарии:
1. Вы уверены , что это тот код, с которым у вас возникли проблемы? Здесь нет разницы между сигнатурой делегата и группой методов, к которой вы пытаетесь ее применить. Это должно скомпилироваться !
2. @Motig: В какой версии .NET вы компилируете? В некоторых более ранних версиях были проблемы с ковариацией, которых нет в более поздних версиях. Это удалось мне в .NET 4.0
3. Этот код в порядке. Повторите попытку.
4. Этот код работает для меня . То же самое относится и к этому варианту , который использует дисперсию.
5. ошибка исправлена … хотя я подозреваю, что я уже знаю, почему она не работает
Ответ №1:
Вы пытаетесь подключить этот метод
public static void DoSomething(Data da, Flight let) {}
в этот делегат
var test = new TravelServiceMethodDelegate(LetService.DoSomething);
Это не может работать. Почему? Рассмотрим следующий код:
class CarRide : ITravelObject { }
void GoForACarRide(TravelServiceMethodDelegate travelService) {
travelService.Invoke(someData, new CarRide());
}
Это компилируется, потому CarRide
что реализует ITravelObject
.
Однако, если я вызову GoForACarRide(test)
, он прервется, поскольку test
указывает на DoSomething
, который ожидает a Flight
.
Ответ №2:
Ваш код не работает, потому что это небезопасно. Вы пытаетесь создать делегат, который утверждает, что он принимает any ITravelObject
, но на самом деле он будет работать только для Flight
. Это небезопасно и поэтому недопустимо.
Однако это будет работать наоборот. Этот код компилируется:
public delegate void TravelServiceMethodDelegate(Data dataAccess, Flight travelObject);
…
var test = new TravelServiceMethodDelegate(LetService.DoSomething);
Ответ №3:
Если бы это было возможно, вы могли бы сделать это:
namespace CovarianceContravarianceTest
{
public interface ITravelObject { }
public class Flight : ITravelObject
{
public void Fly() { }
}
public class Cruise : ITravelObject
{
public void Sail() { }
}
public static class LetService
{
public static void GoFlying(Flight flight)
{
flight.Fly();
}
public static void GoSailing(Cruise cruise)
{
cruise.Sail();
}
}
public delegate void TravelServiceMethodDelegate(ITravelObject travelObject);
class Program
{
static void Main(string[] args)
{
var test = new TravelServiceMethodDelegate(LetService.GoFlying);
test(new Cruise());
}
}
}
Очевидно, что передача a cruise
в GoFlying()
не сработает. A Cruise
не является a Flight
.