Как работает GetValueOrDefault?

Я отвечаю за поставщика LINQ, который выполняет некоторую оценку кода С# во время выполнения. В качестве примера:

int? thing = null;
accessor.Product.Where(p => p.anInt == thing.GetValueOrDefault(-1))

В настоящее время вышеуказанный код не работает с моим провайдером LINQ из-за того, что thing имеет значение null.

Пока я работал с С# в течение длительного времени, я не знаю, как реализуется GetValueOrDefault, и поэтому я должен решить эту проблему.

Итак, мой вопрос: как работает GetValueOrDefault в том случае, если экземпляр, на который он был вызван, равен нулю? Почему не выбрано NullReferenceException?

А следуйте по вопросу: как мне нужно повторить вызов GetValueOrDefault с помощью отражения, учитывая, что мне нужно обрабатывать нулевые значения.

Ответ 1

thing не null. Поскольку structs не может быть null, поэтому не может Nullable<int> быть null.

Дело в том, что это просто магия компилятора. Вы думаете, что это null. На самом деле, HasValue просто установлен на false.

Если вы вызываете GetValueOrDefault, он проверяет, есть ли HasValue true или false:

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

Ответ 2

A NullReferenceException не выбрасывается, потому что ссылки нет. GetValueOrDefault - это метод в структуре Nullable<T>, поэтому вы используете его, это тип значения, а не ссылочный тип.

Метод GetValueOrDefault(T) просто реализуется следующим образом:

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

Итак, чтобы воспроизвести поведение, вам просто нужно проверить свойство HasValue, чтобы узнать, какое значение использовать.

Ответ 3

Я думаю, что ваш провайдер работает неправильно. Я сделал простой тест, и он работал правильно.

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

Он выводит как результат: Продукт -1 - -1