.NET Core 和 .NET Framework 之间 DateTime 的 Expression.Subtract 差异
Difference in Expression.Subtract for DateTime between .NET Core and .NET Framework
在将我的 .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
:
The binary operator Subtract is not defined for the types
'System.DateTime' and 'System.DateTime'.
但是,对于两个目标,以下代码都有效:
DateTime one = new DateTime();
DateTime two = new DateTime();
TimeSpan difference = one - two;
因此我希望表达式树也能为 .NET Core 编译?是我做错了什么,还是is this a bug in .NET Core?
这是 System.Linq.Expressions
程序集中的错误。
这些方法用于查找 Subtract 运算符方法:
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
,然后就失败了,因为输入类型不匹配。
在 .NET 4.5 中,它们通过传递参数类型以正确的方式进行搜索:
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 移植到核心时,某些 API 在 .NET Core 中不可用,因此开发了自定义实现,但从未被捕获。
我已经 sent a PR to 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;
}
在将我的 .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
:
The binary operator Subtract is not defined for the types 'System.DateTime' and 'System.DateTime'.
但是,对于两个目标,以下代码都有效:
DateTime one = new DateTime();
DateTime two = new DateTime();
TimeSpan difference = one - two;
因此我希望表达式树也能为 .NET Core 编译?是我做错了什么,还是is this a bug in .NET Core?
这是 System.Linq.Expressions
程序集中的错误。
这些方法用于查找 Subtract 运算符方法:
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
,然后就失败了,因为输入类型不匹配。
在 .NET 4.5 中,它们通过传递参数类型以正确的方式进行搜索:
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 移植到核心时,某些 API 在 .NET Core 中不可用,因此开发了自定义实现,但从未被捕获。
我已经 sent a PR to 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;
}