Co (ntra) дисперсия в параметре делегата - PullRequest
1 голос
/ 03 ноября 2011

Я хочу создать делегата, указывающего на статическую функцию ... статическая функция имеет второй параметр типа 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' соответствует делегату 'CovarianceContravarianceTest.TravelServiceMethodDelegate'

спасибо всем за ответы, я уже понял, что это даже не проблема ковариации / контравариантности

Ответы [ 3 ]

2 голосов
/ 03 ноября 2011

Вы пытаетесь подключить этот метод

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, что предполагает Flight.

1 голос
/ 03 ноября 2011

Если бы это было возможно, вы могли бы сделать это:

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());
        }
    }
}

Передача cruise в GoFlying(), очевидно, не будет работать.A Cruise не Flight.

1 голос
/ 03 ноября 2011

Ваш код не работает, потому что он небезопасен. Вы пытаетесь создать делегата, который утверждает, что он принимает любой ITravelObject, но на самом деле он будет работать только для Flight. Это небезопасно и поэтому запрещено.

Впрочем, все будет работать наоборот. Этот код компилируется:

public delegate void TravelServiceMethodDelegate(Data dataAccess, Flight travelObject);

…

var test = new TravelServiceMethodDelegate(LetService.DoSomething);
...