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

但是,重载决议当然不考虑类型约束,所以你不能同时拥有两者。有针对这个的解决方法吗?

4

2 回答 2

8

但是当然重载决议不看类型约束

嗯,它确实......但不是方法本身的类型约束。它着眼于参数类型的类型约束。

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

请参阅此博客文章,了解有关这种可怕的骇客攻击的更多详细信息。

就我个人而言,我可能只是以不同的方式命名这两种方法,这样重载解析就不需要那么辛苦了——你的代码的读者也不需要。

于 2012-07-09T19:26:55.407 回答
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?);
于 2012-07-17T19:56:06.943 回答