2015-04-14 10 views
11

Ich bin verantwortlich für einen LINQ-Anbieter, der einige Laufzeitauswertung von C# -Code durchführt. Als Beispiel:Wie funktioniert GetValueOrDefault?

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

Zur Zeit der obige Code mit meinem LINQ-Anbieter nicht aufgrund thing null arbeiten zu sein.

Während ich mit C# für eine lange Zeit arbeite, weiß ich nicht, wie GetValueOrDefault implementiert ist und daher, wie ich das beheben sollte.

Meine Frage ist also: Wie funktioniert GetValueOrDefault in dem Fall, dass die Instanz, auf die es aufgerufen wird, null ist? Warum wird kein NullReferenceException geworfen?

Eine weitere Frage: Wie gehe ich vor, um einen Anruf auf GetValueOrDefault mit Reflektion zu replizieren, vorausgesetzt, dass ich mit Nullwerten umgehen muss.

+6

Die 'Nullable <>' struct Besonderes ist. Eine Struktur zu sein bedeutet, dass sie nicht wirklich 'null' sein kann, aber die Sprache erlaubt es, sie auf 'null' zu setzen, wodurch nur eine Instanz mit 'HasValue' auf false gesetzt wird. 'GetValueOrDefault' funktioniert hier wahrscheinlich nicht, weil Sie EF (oder einen anderen Abfrageanbieter) verwenden, der nicht weiß, wie er in SQL übersetzt wird. – juharr

+3

was meinst du mit "es funktioniert nicht"? – Default

+0

"funktioniert nicht" - was genau passiert? –

Antwort

13

thing ist nicht null. Da Strukturen nicht null sein können, so kann Nullable<int> nicht null sein.

Das Ding ist ... es ist nur Compiler Magie. Sie denken ist es null. In der Tat ist die HasValue nur auf false festgelegt.

Wenn Sie GetValueOrDefault nennen es überprüft, ob HasValue ist true oder false:

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

Wenn Sie jedoch reflection verwenden, um den Wert einer Instanz von Null Nullable abzurufen, wird tatsächlich null zurückgegeben. –

+0

Es ist immer noch Magie im Compiler/Debugger usw.Die Interna verschleiern, was tatsächlich passiert. Siehe den Link zur Referenzquelle in meiner Antwort. –

+0

Ok, wenn es um die Reflektion geht, muss ich nur die CLR replizieren, indem ich prüfe, ob der Typ ein Nullable <> ist, und eine Instanz mit HasValue manuell auf false setzen. Vielen Dank! –

0

A NullReferenceException nicht geworfen wird, weil es keine Referenz. Die GetValueOrDefault ist eine Methode in der Nullable<T> Struktur, also, was Sie verwenden, ist ein Werttyp, kein Referenztyp.

Die GetValueOrDefault(T) method is simply implemented like this:

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

Also, um das Verhalten zu replizieren Sie müssen nur die HasValue Eigenschaft überprüfen, um zu sehen, was Wert zu verwenden.

+0

Ich kann 'HasValue' nicht überprüfen, wenn Reflektion verwendet wird, da die zurückgegebene Instanz tatsächlich null ist. –

+0

@IanNewson: Es klingt, als würde die Instanz erhalten, dass Sie den Wert der Variable erhalten. Das würde den Wert erhalten und in ein Objekt umwandeln. Sie sollten sich die Variable selbst ansehen, anstatt ihren Wert zu erhalten. – Guffa

-1

Ich denke, Sie Provider funktionierte nicht richtig. Ich habe einen einfachen Test gemacht und es hat richtig funktioniert.

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

Es erzeugt als Ausgabe: Produkt -1 - -1

+0

Entschuldigung, ich denke, Sie haben missverstanden, ich bin der Autor des Link-Providers in diesem Fall. Ich weiß, es funktioniert gut mit Linq zu Objekten wie in Ihrem Beispiel. –

+0

Deshalb habe ich gesagt "Ich denke, dass Ihr Provider nicht richtig funktioniert.". Ihre Frage war die Funktionalität von "GetValueOrDefault für den Fall, dass die Instanz, in der es aufgerufen wird, null ist". –

+0

@CharlesSchneider Ziemlich viele Abfrage-Provider, * by design *, unterstützen nicht jede mögliche Operation, die Sie in LINQ zu Objekten durchführen könnten. Einige werden absichtlich nicht unterstützt, in der Regel aufgrund der Art des Abfrageanbieters und dem, was tatsächlich abgefragt wird, wenn eine Übersetzung des angegebenen Ausdrucks für die von ihm repräsentierte Datenquelle nicht möglich ist. – Servy