我有这个功能:
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 :(得分: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 :(得分: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?);