Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Contravariance interface implementation order

Tags:

c#

interface

Take this piece of code:

using System;

public class Program
{
    interface IVisitable<T> { 
        void Accept(object o);
    }

    interface IVisitor<in T> {
        void Visit(T t);
    }

    class IntAndDoubleVisitable: IVisitable<int>, IVisitable<double>
    {
        public void Accept(object o) {
            if (o is IVisitor<IntAndDoubleVisitable>) {
                ((IVisitor<IntAndDoubleVisitable>)o).Visit(this);
            }
        }
    }

    class SingleVisitor<T>: IVisitor<T> {
        public void Visit(T visitor) {
            Console.WriteLine(typeof(T).FullName);
        }
    }

    class DoubleVisitor1: IVisitor<IVisitable<int>>, IVisitor<IVisitable<double>> {
        void IVisitor<IVisitable<int>>.Visit(IVisitable<int> t) {
            Console.WriteLine("Int");
        }

        void IVisitor<IVisitable<double>>.Visit(IVisitable<double> t) {
            Console.WriteLine("Double");
        }
    }

    class DoubleVisitor2: IVisitor<IVisitable<double>>, IVisitor<IVisitable<int>> {
        void IVisitor<IVisitable<int>>.Visit(IVisitable<int> t) {
            Console.WriteLine("Int");
        }

        void IVisitor<IVisitable<double>>.Visit(IVisitable<double> t) {
            Console.WriteLine("Double");
        }
    }

    public static void Main()
    {
        var visitable = new IntAndDoubleVisitable();
        visitable.Accept(new SingleVisitor<IVisitable<int>>()); // Fine
        visitable.Accept(new SingleVisitor<IVisitable<double>>()); // Fine
        visitable.Accept(new DoubleVisitor1()); // ?
        visitable.Accept(new DoubleVisitor2()); // ?
    }
}

How will the least two calls be handled?

By making few tests, I can say that the first call (DoubleVisitor1) writes "Int" and the second writes "Double", but I couldn't find anything online except a post by Eric Lippert teasing about what would the same situation cause if used in IEnumerable. It would be nice to have a reference from the language or from Microsoft documentation.

like image 778
marco6 Avatar asked Sep 01 '26 01:09

marco6


1 Answers

At the IL level, the behavior is defined in ECMA 335 (II.12.2) to be in declaration order referring to the IL declaration tables. However, AFAIK C# doesn't formally guarantee to preserve interface declaration order from C# into the IL, so:

  • it happens to be declaration order today
  • but it would be prudent to consider this an undefined behavior, and not rely on it
  • and in particular, note that C# can have undefined declaration order anyway (see: partial class)
like image 187
Marc Gravell Avatar answered Sep 03 '26 15:09

Marc Gravell



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!