简体   繁体   English

.NET Core和.NET Framework之间的DateTime的Expression.Subtract的差异

[英]Difference in Expression.Subtract for DateTime between .NET Core and .NET Framework

While converting my .NET 4.5 library to .NETStandard v1.6 I ran into a failing unit test which used to pass before. 在将我的.NET 4.5库转换为.NETStandard v1.6我遇到了一个以前通过的失败单元测试。

I pinpointed the problem to the following three lines of code: 我将问题确定为以下三行代码:

ParameterExpression arg1 = Expression.Parameter( typeof( DateTime ), "arg1" );
ParameterExpression arg2 = Expression.Parameter( typeof( DateTime ), "arg2" );
var test = Expression.Subtract( arg1, arg2 );

This expression tree compiles for .NET 4.5 , but throws an InvalidOperationException in .NETStandard v1.6 : 此表达式树为.NET 4.5编译,但在.NETStandard v1.6抛出InvalidOperationException

The binary operator Subtract is not defined for the types 'System.DateTime' and 'System.DateTime'. 没有为类型'System.DateTime'和'System.DateTime'定义二元运算符Subtract。

However, for both targets the following code works: 但是,对于这两个目标,以下代码有效:

DateTime one = new DateTime();
DateTime two = new DateTime();
TimeSpan difference = one - two;

I thus would expect the expression trees to compile for .NET Core as well? 因此,我希望表达式树也可以为.NET Core编译? Am I doing something wrong, or is this a bug in .NET Core ? 我做错了什么,或者这是.NET Core中的错误

It's a bug in System.Linq.Expressions assembly. 这是System.Linq.Expressions程序集中的一个错误。

These methods are used to find the Subtract operator method: 这些方法用于查找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;
}

As you see, the GetAnyStaticMethod picks randomly the first "op_Subtraction" method from DateTime , instead of looping through all available, where DateTime has two of such operator methods: 如您所见, GetAnyStaticMethodDateTime随机选取第一个“op_Subtraction”方法,而不是循环遍历所有可用的方法,其中DateTime有两个这样的运算符方法:

public static DateTime operator -(DateTime d, TimeSpan t);
public static TimeSpan operator -(DateTime d1, DateTime d2);

So the code picks the wrong one that takes in DateTime and TimeSpan , then just fails because input types don't match. 所以代码选择了错误的一个接受DateTimeTimeSpan ,然后失败因为输入类型不匹配。

In .NET 4.5 they do search in a proper way by passing argument types: 在.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);

This is indeed a bug in the implementation of .NET Core. 这确实是.NET Core实现中的一个错误。 The reason is that certain APIs were not avaiable in .NET Core when System.Linq.Expressions was ported to core, so a custom implementation was developed and this was never caught. 原因是当System.Linq.Expressions被移植到核心时,某些API在.NET Core中是不可用的,因此开发了一个自定义实现,并且从未捕获过。

I've sent a PR to dotnet/corefx to fix this. 我已经发送了一个PR到dotnet / corefx来解决这个问题。 For the curious, the problem was that the method finding the operator loops through the methods, but breaks out of the loop when it finds a match, before checking that the method is the one we want. 对于好奇的问题是,找到运算符的方法循环遍历方法,但在找到匹配之前突破循环,然后检查方法是否是我们想要的方法。 The fix is to move parameter checking inside the loop, eg 修复是在循环内移动参数检查,例如

        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;
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 ASP.NET Core(.NET Core)和ASP.NET Core(.NET Framework)之间的区别 - Difference between ASP.NET Core (.NET Core) and ASP.NET Core (.NET Framework) 完整 .NET 框架和 .NET 核心之间 lambda 表达式的差异 - Difference in lambda expressions between full .NET framework and .NET Core 创建项目 ASP.NET Core (.NET Core) 和 ASP.NET Core (.NET Framework) 有什么区别 - What is the difference between creating a project ASP.NET Core (.NET Core) and ASP.NET Core (.NET Framework) 如何调试 Expression.Lambda? (.net 核心 2.1 和 .net 核心 3.1 之间表达式树评估的差异) - How to debug Expression.Lambda? (Difference in Expressions tree evaluation between .net core 2.1 and .net core 3.1) CultureInfo 在 .NET 核心和 .NET 框架之间有所不同 - CultureInfo differs between .NET Core and .NET Framework .Net DateTime.Subtract问题 - .Net DateTime.Subtract Issue 使用 ASP.NET Core Web 应用程序 (.NET Core) 并将 net461 设置为唯一框架与使用 (.NET Framework) 模板之间的区别 - Difference between using the ASP.NET Core Web Application (.NET Core) with net461 set as the only framework and using the (.NET Framework) template “.NET Core”和“.NET Core App”有什么区别? - What is the difference between `.NET Core` and `.NET Core App`? IdentityRole和IdentityUser之间的净核心差异 - Net Core Difference between IdentityRole and IdentityUser .NET中的lambda表达式和谓词有什么区别? - What is the difference between a lambda expression and a predicate in .NET?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM