表达差异.减去.net Core和.net Framework之间的DateTime
本文关键字:net Framework 之间 DateTime Core 减去 | 更新日期: 2023-09-27 18:08:01
在将我的.NET 4.5
库转换为.NETStandard v1.6
时,我遇到了一个失败的单元测试,该单元测试以前是通过的。
我将问题定位到以下三行代码:
ParameterExpression arg1 = Expression.Parameter( typeof( DateTime ), "arg1" );
ParameterExpression arg2 = Expression.Parameter( typeof( DateTime ), "arg2" );
var test = Expression.Subtract( arg1, arg2 );
此表达式树编译.NET 4.5
,但在.NETStandard v1.6
中抛出InvalidOperationException
:
但是,对于两个目标,下面的代码都可以工作:没有为这些类型定义二进制操作符Subtract的系统。DateTime'和'System.DateTime'.
DateTime one = new DateTime();
DateTime two = new DateTime();
TimeSpan difference = one - two;
我因此会期望表达式树编译为。net核心以及?是我做错了什么,还是这是一个错误在。net核心?
这是System.Linq.Expressions
汇编中的一个错误。
这些方法用于查找减法操作符方法:
public static MethodInfo GetAnyStaticMethodValidated(this Type type, string name, Type[] types)
{
// Method name is "op_Subtraction" in your case
MethodInfo anyStaticMethod = type.GetAnyStaticMethod(name);
// DateTime and DateTime in your case
if (!anyStaticMethod.MatchesArgumentTypes(types))
{
return null;
}
return anyStaticMethod;
}
public static MethodInfo GetAnyStaticMethod(this Type type, string name)
{
foreach (MethodInfo current in type.GetRuntimeMethods())
{
if (current.IsStatic && current.Name == name)
{
return current;
}
}
return null;
}
如您所见,GetAnyStaticMethod
随机从DateTime
中选择第一个"op_Subtraction"方法,而不是循环遍历所有可用的方法,其中DateTime
有两个这样的操作符方法:
public static DateTime operator -(DateTime d, TimeSpan t);
public static TimeSpan operator -(DateTime d1, DateTime d2);
所以代码选择了错误的DateTime
和TimeSpan
,然后因为输入类型不匹配而失败。
Type[] types = new Type[]
{
leftType, // DateTime in your case
rightType // DateTime in your case
};
BindingFlags bindingAttr = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
// Method name is "op_Subtraction" in your case
MethodInfo methodInfo = nonNullableType.GetMethodValidated(name, bindingAttr, null, types, null);
这确实是。net Core实现中的一个bug。原因是,当System.Linq.Expressions被移植到Core时,某些api在。net Core中是不可用的,所以开发了一个自定义实现,而这从未被捕获。
我已经发送PR到dotnet/corefx来解决这个问题。对于好奇的人来说,问题是寻找操作符的方法循环遍历方法,但在找到匹配项之前,在检查该方法是否是我们想要的方法之前,就跳出了循环。修复方法是将参数检查移到循环内部,例如
internal static MethodInfo GetAnyStaticMethodValidated(
this Type type,
string name,
Type[] types)
{
foreach (var method in type.GetRuntimeMethods())
{
if (method.IsStatic && method.Name == name && method.MatchesArgumentTypes(types))
{
return method;
}
}
return null;
}