2012-07-09 38 views
0

我有這樣的功能:實現用於可空<>一元綁定*和*引用類型

public static U? IfNotNull<T, U>(this T? self, Func<T, U?> func) 
    where T : struct 
    where U : struct 
{ 
    return (self.HasValue) ? func(self.Value) : null; 
} 

實施例:

int? maybe = 42; 
maybe.IfNotNull(n=>2*n); // 84 

maybe = null; 
maybe.IfNotNull(n=>2*n); // null 

我希望它的工作就隱含地爲空的引用類型以及明確的Nullable<>類型。此實現將工作:

public static U IfNotNull<T, U>(this T? self, Func<T, U> func) 
    where T : struct 
    where U : class 
{ 
    return (self.HasValue) ? func(self.Value) : null; 
} 

但當然重載不看類型的限制,所以你不能同時兼得。有針對這個的解決方法嗎?

+0

難道你不能只刪除where子句? – 2012-07-09 19:24:15

+0

你可以簡單的重命名第二個函數。如果問題是不同的返回類型... – rekire 2012-07-09 19:25:58

+0

否:第一個函數中的'U'必須聲明'struct'爲'Nullable'',並且第二個函數中的'U'必須聲明爲class '這樣'null'可以作爲'U'返回。 – 2012-07-09 19:28:16

回答

7

但當然重載不看類型約束

好它......但不是方法本身的類型限制。它查看參數類型的類型限制。

在C#4(其可選參數),你可以做到這一點......但我真的建議你不要:

public class MustBeStruct<T> where T : struct {} 
public class MustBeClass<T> where T : class {} 

public static U? IfNotNull<T, U>(this T? self, Func<T, U?> func, 
         MustBeStruct<U> ignored = default(MustBeStruct<U>)) 
    where T : struct 
    where U : struct 
{ 
    return (self.HasValue) ? func(self.Value) : null; 
} 

public static U IfNotNull<T, U>(this T? self, Func<T, U> func, 
           MustBeClass<U> ignored = null) 
    where T : struct 
    where U : class 
{ 
    return (self.HasValue) ? func(self.Value) : null; 
} 

這個可怕的更多詳細信息,請參閱this blog post ,可怕的黑客。

就我個人而言,我可能會以不同的方式命名這兩種方法,以便重載解析不需要如此努力 - 而且您的代碼讀者也不需要這麼做。

+1

這是我一段時間以來看到的最差的答案。我印象深刻,感到震驚。 – 2012-07-09 19:36:02

+1

@ThomSmith:我的工作已經完成。 – 2012-07-09 19:40:44

0

所以我結束了這一點:

public static U IfNotNull<T, U>(this T self, Func<T, U> func) 
    where U : class 
{ 
    return (self != null) 
     ? func(self) 
     : (U)null; 
} 

public static U? IfNotNull<T, U>(this T self, Func<T, U?> func) 
    where U : struct 
{ 
    return (self != null) 
     ? (U?)func(self) 
     : null; 
} 

過載變壓器似乎很樂​​意與此有關。這是Nullable<>類型的額外工作的一小部分:

object o = null; 
o.IfNotNull(x => x.ToString()); 
o.IfNotNull(x => x.GetHashCode() as int?); 

int? i = null; 
i.IfNotNull(x => Math.Abs(x.Value).ToString()); 
i.IfNotNull(x => Math.Abs(x.Value) as int?); 
相關問題