为了账号安全,请及时绑定邮箱和手机立即绑定

Lambda 不能进行 Int16 比较吗?

Lambda 不能进行 Int16 比较吗?

C#
慕尼黑5688855 2023-09-09 16:34:42
lambda expression我的 C# (.NET 4.7.1) 代码中有以下内容:DataRow[] skmRows = dtSKM.AsEnumerable().Where(x =>    x.Field<int>("NDRAWING1").Equals(NDRAWING1) &&    x.Field<Int16>("NDRAWING2").Equals(NDRAWING2)    ).ToArray();一切都会编译,并且在运行时不会引发异常。问题是上面的 lambda 表达式应该得到结果,但事实并非如此。我停在断点处并验证DataRows应该已经发生匹配。然后我将这个表达式复制到Immediate窗口中VS2017并运行它——它确实获得了匹配的数据行。啥??然后我就想知道这一点Int16。MSSQL 中的相关列是 a SMALLINT,它映射到 C# 中的 INT16。为了好玩,我将 sql server 中的数据类型从smallint更改为int,并因此更改了我的lambda:DataRow[] skmRows = dtSKM.AsEnumerable().Where(x =>    x.Field<int>("NDRAWING1").Equals(NDRAWING1) &&    x.Field<int>("NDRAWING2").Equals(NDRAWING2)    ).ToArray();...它成功了!(我按预期得到了匹配的行。)这让我得出结论,.NET 中存在一个错误,运行时无法正确评估 Int16 与smallint sql server 列值的比较。除了bug还有解释吗?我猜这对任何人来说都应该很容易重现。启动一个 lambda 来匹配 MSSQL 中的 SMALLINT 列,看看会发生什么。
查看完整描述

1 回答

?
沧海一幻觉

TA贡献1824条经验 获得超5个赞

确实,smallint映射到int16又名Short。您可以在adonet 服务器数据类型映射处验证它。至于发生了什么,请检查 int16 equals 的文档:“如果 obj 是 Int16 的实例并且等于该实例的值,则为 true;否则为 false。” 。

变量NDRAWING2也需要是int16 。在Javascript中,有运算符“===”来表示值和类型必须相同。


通过正确的抽象,使用 Microsoft.EntityFrameworkCore.InMemory 2.2.6 和 NUnit 3.2,我将:

  • 在内存数据库上下文中创建

  • 添加上下文到服务

  • 使用服务添加一些数据并将它们存储到数据库

  • 验证它在新上下文中是否有一些数据

  • 使用服务查找我想要的数据

  • 验证它确实找到了数据

代码示例:

class Program

{

    static void Main(string[] args)

    {

        var options = new DbContextOptionsBuilder<DtSkmContext>()

            .UseInMemoryDatabase(databaseName: "Add_writes_to_database")

            .Options;


        using (var context = new DtSkmContext(options))

        {

            var service = new DtSkmService(context);

            service.Add(3, 7);

            context.SaveChanges();

        }


        using (var context = new DtSkmContext(options))

        {

            Assert.That(context.DtSkm.Count(), Is.EqualTo(1));


            var service = new DtSkmService(context);

            var result = service.Find(3, 7);


            Assert.That(result, Is.Not.Null);

        }

    }

}

服务


public class DtSkmService

{

    private DtSkmContext _context;


    public DtSkmService(DtSkmContext context)

    {

        _context = context;

    }


    public void Add(int ndrawing1, Int16 ndrawing2)

    {

        var dtSkm = new DtSkmDto { Ndrawing1 = ndrawing1, Ndrawing2 = ndrawing2 };

        _context.DtSkm.Add(dtSkm);

        _context.SaveChanges();

    }


    public IEnumerable<DtSkmDto> Find(int first, Int16 second)

    {

        return _context.DtSkm

            .Where(b => b.Ndrawing1.Equals(first) && b.Ndrawing2.Equals(second))

            .OrderBy(b => b.Ndrawing1)

            .ToList();

    }

}

和 dto 和上下文


public class DtSkmDto

{

    public int Id { get; set; }

    [Required]

    public int Ndrawing1 { get; set; }

    [Required]

    public Int16 Ndrawing2 { get; set; }

}

public class DtSkmContext : DbContext

{

    public DtSkmContext()

    {

    }

    public DtSkmContext(DbContextOptions<DtSkmContext> options) : base(options)

    {

    }

    public DbSet<DtSkmDto> DtSkm { get; set; }

}

虽然这使用 EF core 和内存数据库,但它展示了一种实现方法。根据您的情况,您可以进行一些小的更改:


var data = dtSKM.AsEnumerable().ToList();

DataRow[] skmRows = data.Where(x =>

   x.Field<int>("NDRAWING1").Equals(NDRAWING1) &&

   x.Field<Int16>("NDRAWING2").Equals(NDRAWING2)

   ).ToArray();

您可以使用调试器验证数据实例类型/值。你的假设之一不成立,它不是“.NET 中的错误”。


查看完整回答
反对 回复 2023-09-09
  • 1 回答
  • 0 关注
  • 81 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信