.NET本机代码在构造函数上崩溃了吗?.Invoke()(null-propagation)

时间:2017-05-08 20:53:48

标签: c# .net reflection .net-native null-propagation-operator

在一天中的大部分时间里,我头疼不已后,我偶然发现了使用.NET Native(用于Windows UWP应用程序)编译的.NET代码的一个非常奇怪的问题。

以下代码适用于任何.NET运行时环境,包括Mono,Xamarin等:

public class ABC {}
// ...
var constr = typeof(ABC).GetTypeInfo().DeclaredConstructors.First();

var abc = (ABC) constr?.Invoke(new object[0]);
// abc now contains an instance of ABC

在使用.NET本机编译的Windows UWP上,代码抛出类型为NotImplementedException

的异常

但是,当删除空传播运算符时,它在.NET Native上完美运行:

public class ABC {}
// ...
var constr = typeof(ABC).GetTypeInfo().DeclaredConstructors.First();

var abc1 = (ABC) constr.Invoke(new object[0]);
// abc1 now contains an instance of ABC

// the following line throws an exception on .NET Native
// but it works fine on any other .NET runtime
var abc2 = (ABC) constr?.Invoke(new object[0]);

发生异常的堆栈跟踪中的行是:

at System.Reflection.ConstructorInfo.Invoke(Object[] parameters) 
in f:\dd\ndp\fxcore\CoreRT\src\System.Private.Reflection\src\System\Reflection\ConstructorInfo.cs:line 41

这有点像编译器或运行时中的错误。这里发生了什么?我错过了什么吗?

1 个答案:

答案 0 :(得分:2)

原来这是一个错误。

此处有更多信息:https://github.com/dotnet/corert/issues/3565

  
      
  • System.Reflection引用程序集中的ConstructorInfo.Invoke(object [])方法(C:\ Program Files(x86)\ Reference   大会\微软\ Framework.NETPortable \ V4.5 \资料\ Profile78 \ System.Reflection.dll   说Invoke方法不是虚拟的。
  •   
  • 有人决定该方法应该是虚拟的,并且他们更改了它in the implementation。 C#的引用程序集   代码编译未被触及。
  •   
  • 通常这不是什么大问题,因为C#几乎总是虚拟地调用方法(即使它们不是虚拟的),因为它需要   虚拟调用的副作用(抛出NullReferenceException)   null this。。
  •   
  • 除了使用null传播运算符之外,C#编译器知道NullReferenceException不会发生并且它决定发出正常值   调用指令而不是callvirt来防止不必要的null   校验。正常调用ConstructorInfo.Invoke(object [])   方法导致我们登陆一个永远不应该被调用的方法。
  •   
     

好消息是ConstructorInfo.Invoke(object [])是no longer virtual,是NetStandard 2.0兼容性工作的一部分(   上一个链接是旧快照。那个版本的.NET Native   尚未发货。现在唯一的解决方法是不要让C#   编译器通过避开运算符来优化callvirt到调用。