83 lines
1.4 KiB
C#
83 lines
1.4 KiB
C#
|
interface ICovariant<out T>
|
||
|
{
|
||
|
T Foo { get; }
|
||
|
}
|
||
|
|
||
|
interface IContravariant<in T>
|
||
|
{
|
||
|
int Bar (T bar);
|
||
|
}
|
||
|
|
||
|
interface IBothVariants <out T1, in T2> : ICovariant<T1>, IContravariant<T2>
|
||
|
{
|
||
|
}
|
||
|
|
||
|
interface IInvariant <T> : ICovariant<T>, IContravariant<T>
|
||
|
{
|
||
|
}
|
||
|
|
||
|
class BothVariants <T1, T2> : IBothVariants <T1, T2>
|
||
|
{
|
||
|
public BothVariants (T1 foo)
|
||
|
{
|
||
|
Foo = foo;
|
||
|
}
|
||
|
|
||
|
public T1 Foo { get; private set; }
|
||
|
|
||
|
public int Bar (T2 bar)
|
||
|
{
|
||
|
return bar.GetHashCode () ^ Foo.GetHashCode ();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class Invariant <T> : IInvariant<T> 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<A, C> both = new BothVariants<B,B> (b);
|
||
|
|
||
|
if (both.Bar (c) != (b.GetHashCode () ^ c.GetHashCode ()))
|
||
|
return 1;
|
||
|
|
||
|
IInvariant<B> neither = new Invariant<B> ();
|
||
|
ICovariant<A> co = neither;
|
||
|
if (co.Foo.Fruit != "Banana")
|
||
|
return 2;
|
||
|
|
||
|
IContravariant<C> contra = neither;
|
||
|
if (contra.Bar (c) != c.GetHashCode ())
|
||
|
return 3;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
}
|