C# 为什么LINQtoSQL有时允许我使用函数进行项目,但有时却不允许?
这真让我困惑。我知道LINQtoSQL通过处理表达式树并尝试通过生成的查询转换内容来进行选择,这就是为什么有些函数转换不起作用的原因(这是一个常见的麻烦) 我在代码中遇到了这样一种情况,LINQ to SQL能够通过选择投影调用我的助手函数。。。有时候。事实上,当方法有一个名称时,它就可以工作,但如果它有另一个名称,它就不能工作。我认为下面的程序最好地说明了这一点(这是我能做的最简单的程序):C# 为什么LINQtoSQL有时允许我使用函数进行项目,但有时却不允许?,c#,linq-to-sql,C#,Linq To Sql,这真让我困惑。我知道LINQtoSQL通过处理表达式树并尝试通过生成的查询转换内容来进行选择,这就是为什么有些函数转换不起作用的原因(这是一个常见的麻烦) 我在代码中遇到了这样一种情况,LINQ to SQL能够通过选择投影调用我的助手函数。。。有时候。事实上,当方法有一个名称时,它就可以工作,但如果它有另一个名称,它就不能工作。我认为下面的程序最好地说明了这一点(这是我能做的最简单的程序): 这是一个L2S错误。这是预期的工作 在反编译的源代码中,我发现: private static
这是一个L2S错误。这是预期的工作 在反编译的源代码中,我发现:
private static MethodSupport GetDecimalMethodSupport(SqlMethodCall mc)
{
if (mc.Method.IsStatic)
{
if (mc.Arguments.Count == 2)
{
string str;
if (((str = mc.Method.Name) != null) && ((((str == "Multiply") || (str == "Divide")) || ((str == "Subtract") || (str == "Add"))) || ((str == "Remainder") || (str == "Round"))))
{
return MethodSupport.Method;
}
}
else if (mc.Arguments.Count == 1)
{
string str2;
if (((str2 = mc.Method.Name) != null) && (((str2 == "Negate") || (str2 == "Floor")) || ((str2 == "Truncate") || (str2 == "Round"))))
{
return MethodSupport.Method;
}
if (mc.Method.Name.StartsWith("To", StringComparison.Ordinal))
{
return MethodSupport.Method;
}
}
}
return MethodSupport.None;
}
搜索“到”
:
嗯。。。还有一个地方。也许L2S认为你的值类型是小数。尝试添加第二个参数以中断mc.Arguments.Count==1
条件
无论如何,这是一个错误。这背后没有更深层次的原因。通常情况下,L2S可以在最终选择中执行功能。这是EF仍然缺乏的一个很棒的特性
将其搁置,并尽快迁移到EF。L2S已被放弃。ToValueType是唯一不起作用的字符串吗?如果你说的是真的,我谨慎地假设,这将是一个L2S错误(一个非常不寻常的错误)。通常,L2S可以在最终选择中执行函数。这是EF仍然缺乏的一个非常棒的特性。即使在LINQPad中,我也能够重现您描述的行为,每次您使用以
开始的方法到(区分大小写)时,它都会抛出一个异常。感谢您提供的信息-我感觉这与它如何解释表达式树中的方法名称有关。更改参数计数或更改为实例方法似乎确实可以解决程序问题(尽管计划只重命名该方法并留下好的注释)。此外,它看起来并不像假定我的类型是双精度的,它通过一组GetXMethodSupport
函数运行,但是GetDecimalMethodSupport
应该同时检查IsStatic
和mc.Method.DeclaringType==typeof(decimal)
——这就是其他辅助方法所做的。是的,这就解释了。它认为这是一种“支持方法”。请考虑对用户语音项目进行投票,该项目要求打开源L2S,这样可以容易地修复这样的错误:
using System;
using Sandbox.Data;
using System.Linq;
namespace Sandbox.Console
{
class Program
{
static void Main(string[] args)
{
using (var dataContext = new SandboxDataContext())
{
try
{
var myValueList = dataContext.Numbers.Select(x => new MyValue
{
Type = DoIt(x.Value),
}).ToList();
System.Console.WriteLine("DoIt Succeeded, found {0} results", myValueList.Count);
}
catch (NotSupportedException)
{
System.Console.WriteLine("DoIt Failed, oh noes!");
}
try
{
var myValueList = dataContext.Numbers.Select(x => new MyValue
{
Type = ToValueType(x.Value),
}).ToList();
System.Console.WriteLine("ToValueType Succeeded, found {0} results", myValueList.Count);
}
catch (NotSupportedException)
{
System.Console.WriteLine("ToValueType Failed, oh noes!");
}
System.Console.ReadKey();
}
}
public static MyValueType DoIt(int value)
{
return MyValueType.SpecialType;
}
public static MyValueType ToValueType(int value)
{
return MyValueType.SpecialType;
}
public sealed class MyValue
{
public MyValueType Type { get; set; }
}
public enum MyValueType
{
SpecialType,
}
}
}
private static MethodSupport GetDecimalMethodSupport(SqlMethodCall mc)
{
if (mc.Method.IsStatic)
{
if (mc.Arguments.Count == 2)
{
string str;
if (((str = mc.Method.Name) != null) && ((((str == "Multiply") || (str == "Divide")) || ((str == "Subtract") || (str == "Add"))) || ((str == "Remainder") || (str == "Round"))))
{
return MethodSupport.Method;
}
}
else if (mc.Arguments.Count == 1)
{
string str2;
if (((str2 = mc.Method.Name) != null) && (((str2 == "Negate") || (str2 == "Floor")) || ((str2 == "Truncate") || (str2 == "Round"))))
{
return MethodSupport.Method;
}
if (mc.Method.Name.StartsWith("To", StringComparison.Ordinal))
{
return MethodSupport.Method;
}
}
}
return MethodSupport.None;
}
if (mc.Method.Name.StartsWith("To", StringComparison.Ordinal))