interface ICovariant { T Foo { get; } } interface IContravariant { int Bar (T bar); } interface IBothVariants : ICovariant, IContravariant { } interface IInvariant : ICovariant, IContravariant { } class BothVariants : IBothVariants { public BothVariants (T1 foo) { Foo = foo; } public T1 Foo { get; private set; } public int Bar (T2 bar) { return bar.GetHashCode () ^ Foo.GetHashCode (); } } class Invariant : IInvariant where T : new() { public T Foo { get { return new T (); } } public int Bar (T bar) { return bar.GetHashCode (); } } class A { public virtual string Fruit { get { return "Apple"; } } } class B : A { public override string Fruit { get { return "Banana"; } } } class C : B { public override string Fruit { get { return "Carrot which I know is not a fruit but you better shut up about it before I cut you"; } } } public class Test { public static int Main () { var b = new B (); var c = new C (); IBothVariants both = new BothVariants (b); if (both.Bar (c) != (b.GetHashCode () ^ c.GetHashCode ())) return 1; IInvariant neither = new Invariant (); ICovariant co = neither; if (co.Foo.Fruit != "Banana") return 2; IContravariant contra = neither; if (contra.Bar (c) != c.GetHashCode ()) return 3; return 0; } }