33
44using System ;
55using System . Collections . Generic ;
6+ using System . Runtime . CompilerServices ;
67using System . Runtime . InteropServices ;
78
89using TestLibrary ;
@@ -26,9 +27,9 @@ public interface ITest
2627 int CallImplemented ( ImplementationToCall toCall ) ;
2728 }
2829
29- public interface ITestGeneric < T >
30+ public interface ITestGeneric < in T , out U >
3031 {
31- T ReturnArg ( T t ) ;
32+ U ReturnArg ( T t ) ;
3233 }
3334
3435 public interface IDirectlyImplemented
@@ -127,18 +128,24 @@ Type ITest.GetMyType()
127128 }
128129
129130 [ DynamicInterfaceCastableImplementation ]
130- public interface ITestGenericImpl < T > : ITestGeneric < T >
131+ public interface ITestGenericImpl < T , U > : ITestGeneric < T , U >
131132 {
132- T ITestGeneric < T > . ReturnArg ( T t )
133+ U ITestGeneric < T , U > . ReturnArg ( T t )
133134 {
134- return t ;
135+ if ( ! typeof ( T ) . IsAssignableTo ( typeof ( U ) )
136+ && ! t . GetType ( ) . IsAssignableTo ( typeof ( U ) ) )
137+ {
138+ throw new Exception ( $ "Invalid covariance conversion from { typeof ( T ) } or { t . GetType ( ) } to { typeof ( U ) } ") ;
139+ }
140+
141+ return Unsafe . As < T , U > ( ref t ) ;
135142 }
136143 }
137144
138145 [ DynamicInterfaceCastableImplementation ]
139- public interface ITestGenericIntImpl : ITestGeneric < int >
146+ public interface ITestGenericIntImpl : ITestGeneric < int , int >
140147 {
141- int ITestGeneric < int > . ReturnArg ( int i )
148+ int ITestGeneric < int , int > . ReturnArg ( int i )
142149 {
143150 return i ;
144151 }
@@ -330,40 +337,50 @@ private static void ValidateGenericInterface()
330337 Console . WriteLine ( $ "Running { nameof ( ValidateGenericInterface ) } ") ;
331338
332339 object castableObj = new DynamicInterfaceCastable ( new Dictionary < Type , Type > {
333- { typeof ( ITestGeneric < int > ) , typeof ( ITestGenericIntImpl ) } ,
334- { typeof ( ITestGeneric < string > ) , typeof ( ITestGenericImpl < string > ) } ,
340+ { typeof ( ITestGeneric < int , int > ) , typeof ( ITestGenericIntImpl ) } ,
341+ { typeof ( ITestGeneric < string , string > ) , typeof ( ITestGenericImpl < string , string > ) } ,
342+ { typeof ( ITestGeneric < string , object > ) , typeof ( ITestGenericImpl < object , string > ) } ,
335343 } ) ;
336344
337345 Console . WriteLine ( " -- Validate cast" ) ;
338346
339- // ITestGeneric<int> -> ITestGenericIntImpl
340- Assert . IsTrue ( castableObj is ITestGeneric < int > , $ "Should be castable to { nameof ( ITestGeneric < int > ) } via is") ;
341- Assert . IsNotNull ( castableObj as ITestGeneric < int > , $ "Should be castable to { nameof ( ITestGeneric < int > ) } via as") ;
342- ITestGeneric < int > testInt = ( ITestGeneric < int > ) castableObj ;
347+ // ITestGeneric<int, int> -> ITestGenericIntImpl
348+ Assert . IsTrue ( castableObj is ITestGeneric < int , int > , $ "Should be castable to { nameof ( ITestGeneric < int , int > ) } via is") ;
349+ Assert . IsNotNull ( castableObj as ITestGeneric < int , int > , $ "Should be castable to { nameof ( ITestGeneric < int , int > ) } via as") ;
350+ ITestGeneric < int , int > testInt = ( ITestGeneric < int , int > ) castableObj ;
351+
352+ // ITestGeneric<string, string> -> ITestGenericImpl<string, string>
353+ Assert . IsTrue ( castableObj is ITestGeneric < string , string > , $ "Should be castable to { nameof ( ITestGeneric < string , string > ) } via is") ;
354+ Assert . IsNotNull ( castableObj as ITestGeneric < string , string > , $ "Should be castable to { nameof ( ITestGeneric < string , string > ) } via as") ;
355+ ITestGeneric < string , string > testStr = ( ITestGeneric < string , string > ) castableObj ;
343356
344- // ITestGeneric<string> -> ITestGenericImpl<string>
345- Assert . IsTrue ( castableObj is ITestGeneric < string > , $ "Should be castable to { nameof ( ITestGeneric < string > ) } via is") ;
346- Assert . IsNotNull ( castableObj as ITestGeneric < string > , $ "Should be castable to { nameof ( ITestGeneric < string > ) } via as") ;
347- ITestGeneric < string > testStr = ( ITestGeneric < string > ) castableObj ;
357+ // Validate Variance
358+ // ITestGeneric<string, object> -> ITestGenericImpl<object, string>
359+ Assert . IsTrue ( castableObj is ITestGeneric < string , object > , $ "Should be castable to { nameof ( ITestGeneric < string , object > ) } via is") ;
360+ Assert . IsNotNull ( castableObj as ITestGeneric < string , object > , $ "Should be castable to { nameof ( ITestGeneric < string , object > ) } via as") ;
361+ ITestGeneric < string , object > testVar = ( ITestGeneric < string , object > ) castableObj ;
348362
349- // ITestGeneric<bool> is not recognized
350- Assert . IsFalse ( castableObj is ITestGeneric < bool > , $ "Should not be castable to { nameof ( ITestGeneric < bool > ) } via is") ;
351- Assert . IsNull ( castableObj as ITestGeneric < bool > , $ "Should not be castable to { nameof ( ITestGeneric < bool > ) } via as") ;
352- var ex = Assert . Throws < DynamicInterfaceCastableException > ( ( ) => { var _ = ( ITestGeneric < bool > ) castableObj ; } ) ;
353- Assert . AreEqual ( string . Format ( DynamicInterfaceCastableException . ErrorFormat , typeof ( ITestGeneric < bool > ) ) , ex . Message ) ;
363+ // ITestGeneric<bool, bool > is not recognized
364+ Assert . IsFalse ( castableObj is ITestGeneric < bool , bool > , $ "Should not be castable to { nameof ( ITestGeneric < bool , bool > ) } via is") ;
365+ Assert . IsNull ( castableObj as ITestGeneric < bool , bool > , $ "Should not be castable to { nameof ( ITestGeneric < bool , bool > ) } via as") ;
366+ var ex = Assert . Throws < DynamicInterfaceCastableException > ( ( ) => { var _ = ( ITestGeneric < bool , bool > ) castableObj ; } ) ;
367+ Assert . AreEqual ( string . Format ( DynamicInterfaceCastableException . ErrorFormat , typeof ( ITestGeneric < bool , bool > ) ) , ex . Message ) ;
354368
355369 int expectedInt = 42 ;
356370 string expectedStr = "str" ;
357371
358372 Console . WriteLine ( " -- Validate method call" ) ;
359373 Assert . AreEqual ( expectedInt , testInt . ReturnArg ( 42 ) ) ;
360374 Assert . AreEqual ( expectedStr , testStr . ReturnArg ( expectedStr ) ) ;
375+ Assert . AreEqual ( expectedStr , testVar . ReturnArg ( expectedStr ) ) ;
361376
362377 Console . WriteLine ( " -- Validate delegate call" ) ;
363378 Func < int , int > funcInt = new Func < int , int > ( testInt . ReturnArg ) ;
364379 Assert . AreEqual ( expectedInt , funcInt ( expectedInt ) ) ;
365380 Func < string , string > funcStr = new Func < string , string > ( testStr . ReturnArg ) ;
366381 Assert . AreEqual ( expectedStr , funcStr ( expectedStr ) ) ;
382+ Func < string , object > funcVar = new Func < string , object > ( testVar . ReturnArg ) ;
383+ Assert . AreEqual ( expectedStr , funcVar ( expectedStr ) ) ;
367384 }
368385
369386 private static void ValidateOverriddenInterface ( )
0 commit comments