2013-05-24 12 views
10

Dlaczego pojawia się ten błąd w poniższym kodzie?Typ "T" musi być wartością nie podlegającą zerowaniu, aby można go było użyć jako parametru "T" w typie ogólnym lub metodzie "System.Nullable <T>"

void Main() 
{ 
    int? a = 1; 
    int? b = AddOne(1); 
    a.Dump(); 
} 

static Nullable<int> AddOne(Nullable<int> nullable) 
{ 
    return ApplyFunction<int, int>(nullable, (int x) => x + 1); 
} 

static Nullable<T> ApplyFunction<T, TResult>(Nullable<T> nullable, Func<T, TResult> function) 
{ 
    if (nullable.HasValue) 
    { 
     T unwrapped = nullable.Value; 
     TResult result = function(unwrapped); 
     return new Nullable<TResult>(result); 
    } 
    else 
    { 
     return new Nullable<T>(); 
    } 
} 
+2

I jakie jest pytanie? –

+0

Nie można go teraz przetestować, ale wywołuje się 'ApplyFunction ' zamiast 'ApplyFunction '? –

+2

Dlaczego spadki? Wydaje mi się, że to dobre pytanie. –

Odpowiedz

10

Wystąpił szereg problemów z kodem. Pierwszym z nich jest to, że twoje typy muszą być neutralne. Możesz wyrazić to, podając where T: struct. Będziesz także musiał podać where TResult: struct, ponieważ używasz tego również jako typu zerowego.

Po naprawieniu where T: struct where TResult: struct należy również zmienić typ wartości zwracanej (która była nieprawidłowa) oraz kilka innych rzeczy.

Po zamocowaniu te wszystkie błędy i uproszczenia, można skończyć z tym:

static TResult? ApplyFunction<T, TResult>(T? nullable, Func<T, TResult> function) 
       where T: struct 
       where TResult: struct 
{ 
    if (nullable.HasValue) 
     return function(nullable.Value); 
    else 
     return null; 
} 

pamiętać, że można przepisać Nullable<T> jak T? która sprawia, że ​​rzeczy stają się bardziej czytelne.

Również można napisać, że w jednym sprawozdaniu wykorzystaniem ?: ale nie sądzę, że to tak czytelne:

return nullable.HasValue ? (TResult?) function(nullable.Value) : null; 

Może chcesz umieścić to w metodę rozszerzenia:

public static class NullableExt 
{ 
    public static TResult? ApplyFunction<T, TResult>(this T? nullable, Func<T, TResult> function) 
     where T: struct 
     where TResult: struct 
    { 
     if (nullable.HasValue) 
      return function(nullable.Value); 
     else 
      return null; 
    } 
} 

Następnie można napisać kod w następujący sposób:

int? x = 10; 
double? x1 = x.ApplyFunction(i => Math.Sqrt(i)); 
Console.WriteLine(x1); 

int? y = null; 
double? y1 = y.ApplyFunction(i => Math.Sqrt(i)); 
Console.WriteLine(y1); 
+2

Zamiast pisać 'nowe TResult?()', Czy nie jest bardziej jasne, aby napisać 'null'? Tak sądzę, jest to filozofia 'Nullable <>. –

+0

@JeppeStigNielsen To na pewno. Zaktualizuję. :) –

+0

Zamiast: return nullable.HasValue? (TResult?) Function (nullable.Value): null; możesz zrobić return nullable ?? null; który jest nieco ładniejszy i czytelniejszy –

6

Jak sugeruje błąd, kompilator nie ma gwarancji, że T nie będzie już możliwe do zniesienia. Trzeba dodać ograniczenie do T:

static Nullable<T> ApplyFunction<T, TResult>(Nullable<T> nullable, 
    Func<T, TResult> function) : where T : struct 
           where TResult : struct 
+0

Będziesz potrzebować więcej zmian, aby to zadziałało. Na przykład TResult również musi być strukturą. –

+0

Prawda, brakowało 'TResult?' Naprawiono :) –