C# GetValuerDefault是如何工作的?

C# GetValuerDefault是如何工作的?,c#,nullable,C#,Nullable,我负责一个LINQ提供者,它对C#代码执行一些运行时评估。例如: int? thing = null; accessor.Product.Where(p => p.anInt == thing.GetValueOrDefault(-1)) 目前,由于thing为空,上述代码无法与我的LINQ提供程序一起使用 虽然我已经使用C#很长时间了,但我不知道GetValueOrDefault是如何实现的,因此我应该如何解决这个问题 所以我的问题是:GetValueOrDefault在调用它的实例为

我负责一个LINQ提供者,它对C#代码执行一些运行时评估。例如:

int? thing = null;
accessor.Product.Where(p => p.anInt == thing.GetValueOrDefault(-1))
目前,由于
thing
为空,上述代码无法与我的LINQ提供程序一起使用

虽然我已经使用C#很长时间了,但我不知道GetValueOrDefault是如何实现的,因此我应该如何解决这个问题

所以我的问题是:
GetValueOrDefault
在调用它的实例为null的情况下如何工作?为什么不抛出
NullReferenceException


一个后续问题:如果我需要处理空值,我应该如何使用反射来复制对
GetValueOrDefault
的调用。

事情
不是
null
。由于结构不能是
null
,因此
null
不能是
null

问题是。。。这就是编译器的魔力。您认为它是空的。实际上,
HasValue
只是设置为
false

如果调用它,则检查
HasValue
是否为
true
false

public T GetValueOrDefault(T defaultValue)
{
    return HasValue ? value : defaultValue;
}

不会抛出
NullReferenceException
,因为没有引用。
GetValueOrDefault
Nullable
结构中的一个方法,因此使用它的是值类型,而不是引用类型

GetValueOrDefault(T)
方法的实现方式如下:

public T GetValueOrDefault(T defaultValue) {
    return HasValue ? value : defaultValue;
}

因此,要复制该行为,您只需检查
HasValue
属性以查看要使用的值。

我认为您的提供者工作不正常。我做了一个简单的测试,它工作正常

using System;
using System.Linq;

namespace ConsoleApp4
{
    class Program
    {
        static void Main(string[] args)
        {
            var products = new Product[] {
                new Product(){ Name = "Product 1", Quantity = 1 },
                new Product(){ Name = "Product 2", Quantity = 2 },
                new Product(){ Name = "Product -1", Quantity = -1 },
                new Product(){ Name = "Product 3", Quantity = 3 },
                new Product(){ Name = "Product 4", Quantity = 4 }
            };

            int? myInt = null;

            foreach (var prod in products.Where(p => p.Quantity == myInt.GetValueOrDefault(-1)))
            {
                Console.WriteLine($"{prod.Name} - {prod.Quantity}");
            }

            Console.ReadKey();
        }
    }

    public class Product
    {
        public string Name { get; set; }
        public int Quantity { get; set; }
    }
}
它作为输出生成:Product-1--1

GetValueOrDefault()
防止由于null而可能发生的错误。如果传入数据为空,则返回0

int-ageValue=age.GetValueOrDefault();//如果年龄==null


ageValue
的值将为零。

可为空的
结构是特殊的。作为一个结构意味着它不可能真正是
null
,但该语言允许您将其设置为
null
,这只会创建一个
HasValue
设置为false的实例
GetValuerDefault
在这里可能不起作用,因为您使用的EF(或其他查询提供程序)不知道如何将其转换为SQL。您所说的“它不起作用”?“不起作用”—到底发生了什么?@RudiVisser抱歉,我想您误解了这个问题。我知道如何解析此特定实例,但我不确定CLR中的哪些内容允许对null类型调用实例方法。也许您应该显示不适用于此情况的Linq提供程序的代码。但是,当使用反射检索null Nullable实例的值时,null实际上是返回的。它在编译器/调试器等中仍然是神奇的。内部代码混淆了实际发生的事情。请参阅我的答案中指向引用源的链接。好的,当涉及到反射时,我只需要通过测试类型是否为可空,并手动创建一个HasValue设置为false的实例来复制CLR。谢谢@伊安·纽森:的确。需要更多的帮助来实现这一点吗?不,谢谢你的提议。最后,我不得不将GetValuerDefault的一个实现硬编码到我的表达式计算器中。远低于理想值,但如果.NET逻辑发生更改,我会感到震惊。在使用反射时,我无法检查
HasValue
,因为返回的实例实际上为空。@IanNewson:听起来获取实例意味着获取变量的值。这将获取值并将其转换为对象。您应该查看变量本身,而不是获取其值。很抱歉,我认为您误解了,我是本例中链接提供程序的作者。我知道它可以很好地与您的示例中的Linq to对象一起工作。这就是为什么我说“我认为您的提供者工作不正常”。您的问题是关于“GetValueOrDefault在其被调用的实例为null的情况下的功能性”。@CharlesSchneider几乎所有查询提供程序都不支持在LINQ to对象中可能执行的所有操作。有些是故意不支持的,通常是由于查询提供程序的性质以及它实际查询的内容使得给定表达式的翻译对于它所表示的数据源是不可能的。