This repository was archived by the owner on Aug 24, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 238
This repository was archived by the owner on Aug 24, 2022. It is now read-only.
C# 7.2 "in" keyword in interfaces #1052
Copy link
Copy link
Open
Description
The in C# 7.2 introduced "in" keyword for method parameters results in a crash when used in an interface, but only if the class that is implementing the interface is cast back to the interface.
The code throws a System.InvalidCastException at runtime (Firefox 57.0.4).
Bug test project:
https://github.com/baehny/Bugs/tree/master/JSIL/JSIL_InParameters/JSIL_InParameters
using System;
public struct TestStruct
{
public int Field;
}
public interface TestInterface
{
void TestMethodRef(ref TestStruct testStruct);
void TestMethodIn(in TestStruct testStruct);
}
public class TestClass : TestInterface
{
public void TestMethodRef(ref TestStruct testStruct) { }
public void TestMethodIn(in TestStruct testStruct) { }
}
class Program
{
static void Main(string[] args)
{
TestStruct testStruct = new TestStruct();
TestClass interfaceClass = new TestClass();
Console.WriteLine("1:");
interfaceClass.TestMethodRef(ref testStruct); //Works
Console.WriteLine("2:");
interfaceClass.TestMethodIn(testStruct); //Works
Console.WriteLine("3:");
((TestInterface)interfaceClass).TestMethodRef(ref testStruct); //Works
Console.WriteLine("4:");
((TestInterface)interfaceClass).TestMethodIn(testStruct); //Crash: throws System.InvalidCastException: Unable to cast object of type 'TestStruct' to type 'ref TestStruct'
Console.WriteLine("End");
}
}
There is no problem when using "ref" which is strange because in both cases the parameter is passed as valuetype TestStruct& but with a System.Runtime.InteropServices.InAttribute for the "in" parameter version. However the in keyword results in two definitions for TestMethodIn()
First version of TestMethodIn :
.method public hidebysig
instance void TestMethodIn (
valuetype TestStruct& testStruct
) cil managed
{
.param [1]
.custom instance void [mscorlib]System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = (
01 00 00 00
)
// Method begins at RVA 0x2050
// Code size 2 (0x2)
.maxstack 8
IL_0000: nop
IL_0001: ret
} // end of method TestClass::TestMethodIn
Second version of TestMethodIn :
.method private final hidebysig newslot virtual
instance void TestInterface.TestMethodIn (
valuetype TestStruct& modreq([mscorlib]System.Runtime.InteropServices.InAttribute) testStruct
) cil managed
{
.override method instance void TestInterface::TestMethodIn(valuetype TestStruct& modreq([mscorlib]System.Runtime.InteropServices.InAttribute) )
.param [1]
.custom instance void [mscorlib]System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = (
01 00 00 00
)
// Method begins at RVA 0x205c
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: call instance void TestClass::TestMethodIn(valuetype TestStruct&)
IL_0007: ret
} // end of method TestClass::TestInterface.TestMethodIn
TestMethodRef :
.method public final hidebysig newslot virtual
instance void TestMethodRef (
valuetype TestStruct& testStruct
) cil managed
{
// Method begins at RVA 0x2050
// Code size 2 (0x2)
.maxstack 8
IL_0000: nop
IL_0001: ret
} // end of method TestClass::TestMethodRef
Calling code:
IL_0037: ldstr "3:"
IL_003c: call void [mscorlib]System.Console::WriteLine(string)
IL_0041: nop
IL_0042: ldloc.1
IL_0043: ldloca.s 0
IL_0045: callvirt instance void TestInterface::TestMethodRef(valuetype TestStruct&)
IL_004a: nop
IL_004b: ldstr "4:"
IL_0050: call void [mscorlib]System.Console::WriteLine(string)
IL_0055: nop
IL_0056: ldloc.1
IL_0057: ldloca.s 0
IL_0059: callvirt instance void TestInterface::TestMethodIn(valuetype TestStruct& modreq([mscorlib]System.Runtime.InteropServices.InAttribute) )
IL_005e: nop
Metadata
Metadata
Assignees
Labels
No labels