【发布时间】:2014-12-10 19:46:07
【问题描述】:
我想按照以下思路编写一个通用方法:
public IEnumerable<T> S<T> (List<T> source)
{
//dosomething with source
if (someCondition)
yield return null;
else
yield return someNonNullItem;
}
T 可以是值类型(例如 int)、可空类型(例如 int?)或 ref 类型(例如字符串)。在所有这三种情况下,我都希望能够返回空值。
//dosomething 块非常通用,涉及转换事物,并且可以与所有类型一起使用而无需修改。同样,(someCondition) 布尔检查没有任何类型依赖。
一些注意事项:
- 我不能使用 default(T),其中 T 是不可为空的值类型(例如 default(T),其中 T 是 int 将不起作用)。需要明确表示 null。
- 我不想从 T 转换为 T?如果我可以避免它,因为源列表可能很长(数百万项)。
目前,我不得不编写三个函数,其中一个函数必须具有不同的名称(因为类型约束不被视为方法签名的一部分)。这三个函数具有相同的主体(为简洁起见未显示)。
public IEnumerable<T?> S<T>(List <T> source) where T:struct
{
}
public IEnumerable<T?> S<T>(List <T?> source) where T : struct
{
}
public IEnumerable<T> S4Ref<T>(List <T> source) where T : class
{
}
在前两种方法中,我需要 T:struct 约束才能返回 Nullable。在第三种方法中:(a) 我需要一个新名称 S4Ref,以避免与第一种方法发生冲突,并且,(b) 我需要 T:class 约束才能返回 null。
实际上,我要写很多这样的S方法,如果按照上面的方法,我将不得不为它们分别写三个版本。我也会把它们变成 List 的扩展方法
问题:
- 有没有办法让一个通用函数做到这一点?或者至少从 3 种方法减少到 2 种方法?
- 如果不是,消除函数体中重复的最佳方法是什么?
目前我正在转向使用 T4 模板来解决这个问题。
【问题讨论】:
-
我强烈考虑首先重新评估产生
null值的设计,或者至少要求方法的调用者传入一个可为空的类型,留下从不可为空到可空的转换是他们的责任。 -
我认为没有比这两种方法更好的方法了——基本上是
IEnumerable<T?>一种,以及一种IEnumerable<T>对T没有限制。如果它有一个不同的名字,你会“相信”你的调用者不要用不可为空的值类型来调用它吗? -
@Fenchurch 您可以使用
null以外的其他内容来表示它。这就是重点。 -
确实,没有什么可以阻止您创建一个
Optional<T>结构,其中T不受约束 - 然后您可以只使用一个方法返回一个IEnumerable<Optional<T>>。 -
我不明白。当您想要返回 null 时,您的理想代码返回 int 是什么?