【问题标题】:A single generic solution?一个通用的解决方案?
【发布时间】: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) 布尔检查没有任何类型依赖。

一些注意事项:

  1. 我不能使用 default(T),其中 T 是不可为空的值类型(例如 default(T),其中 T 是 int 将不起作用)。需要明确表示 null。
  2. 我不想从 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 的扩展方法

问题:

  1. 有没有办法让一个通用函数做到这一点?或者至少从 3 种方法减少到 2 种方法?
  2. 如果不是,消除函数体中重复的最佳方法是什么?

目前我正在转向使用 T4 模板来解决这个问题。

【问题讨论】:

  • 我强烈考虑首先重新评估产生null 值的设计,或者至少要求方法的调用者传入一个可为空的类型,留下从不可为空到可空的转换是他们的责任。
  • 我认为没有比这两种方法更好的方法了——基本上是IEnumerable&lt;T?&gt; 一种,以及一种IEnumerable&lt;T&gt;T 没有限制。如果它有一个不同的名字,你会“相信”你的调用者不要用不可为空的值类型来调用它吗?
  • @Fenchurch 您可以使用null 以外的其他内容来表示它。这就是重点。
  • 确实,没有什么可以阻止您创建一个 Optional&lt;T&gt; 结构,其中 T 不受约束 - 然后您可以只使用一个方法返回一个 IEnumerable&lt;Optional&lt;T&gt;&gt;
  • 我不明白。当您想要返回 null 时,您的理想代码返回 int 是什么?

标签: c# generics nullable


【解决方案1】:

您已经为自己设置了相互冲突的约束。在问题定义中,您说您想要一个适用于值类型(即 int)但能够返回 null 而不会将其转换为可为 null 的类型的函数。作为一种设计范式,我不希望一个集合包含一些不存在的东西。是的,我说过。对我来说,返回一个 null 项意味着它不存在,但你返回的是 null。如果函数S的目的是过滤item,最好跳过不匹配的item,返回下一个。

例如,IEnumerable 的典型用法是如下所示的代码:

    List<int> myList = ....  // somehow fill the list
    foreach(int element in S(myList))
    {
         // do something with the int element.  What should I expect to do with a null
         // even if you could return one?  The only thing I could reasonable do here is
         // skip it.  I have no idea which element of myList the null corresponds to

    }

换句话说,即使 foreach 看起来像这样:

    foreach(int? element in S(myList))

我仍然不知道如何处理元素的空值。仍然没有上下文可以知道 myList 的哪个元素导致函数 S 为 null。

【讨论】:

  • 感谢您的反馈。澄清一下:我不想在处理之前将输入 List 转换为 List 。处理输入后,该值将丢失。
猜你喜欢
  • 2012-03-31
  • 1970-01-01
  • 2021-05-20
  • 1970-01-01
  • 2011-08-13
  • 1970-01-01
  • 1970-01-01
  • 2012-10-07
  • 1970-01-01
相关资源
最近更新 更多