Miroslav
Miroslav

Reputation: 4695

Co(ntra)variance in an parameter of a delegate

I want to create a delegate pointing to a static function...the static function has a second parameter of type Flight, the Flight class implements ITravelObject interface and the second delegate parameter requires this interface.

The following code doesn't work. Why is that? Is there any other possible implementation?

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

}

This results in error

No overload for 'DoSomething' matches delegate 'CovarianceContravarianceTest.TravelServiceMethodDelegate'

thanks everyone for answers, I've already figured out this isn't even a covariance/contravariance issue

Upvotes: 1

Views: 172

Answers (3)

Igby Largeman
Igby Largeman

Reputation: 16747

If that were possible, you could do this:

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

Passing a cruise to GoFlying() obviously would't work. A Cruise isn't a Flight.

Upvotes: 1

Heinzi
Heinzi

Reputation: 172390

You are trying to plug this method

public static void DoSomething(Data da, Flight let) {} 

into this delegate

var test = new TravelServiceMethodDelegate(LetService.DoSomething);

This cannot work. Why? Consider the following code:

class CarRide : ITravelObject { }

void GoForACarRide(TravelServiceMethodDelegate travelService) {
    travelService.Invoke(someData, new CarRide());
}

This compiles, because CarRide implements ITravelObject.

However, if I call GoForACarRide(test), it will break, since test points to DoSomething, which expects a Flight.

Upvotes: 2

svick
svick

Reputation: 244948

Your code doesn't work, because it's not safe. You are trying to create a delegate that claims that it accepts any ITravelObject, but it would actually work only for Flight. This is not safe and so it's not allowed.

It would work the other way round, though. This code compiles:

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

…

var test = new TravelServiceMethodDelegate(LetService.DoSomething);

Upvotes: 1

Related Questions