Co (ntra) отклонение в параметре делегата

#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 .