【问题标题】:How do I create a generic method with nested T's?如何创建带有嵌套 T 的泛型方法?
【发布时间】:2011-04-08 20:28:53
【问题描述】:

我有一个通用的扩展方法

public static IList<T> Replace<T>(this IList<T> source, Ilist<T> newList) where T:IStateful

我用

调用
myStatefulSetOfStuff = myStatefulSetOfStuff.Replace(GetNewSetOfStuff());

不过,我意识到我的方法适用于所有实现 ICollection 的集合,因此我将其更改为

public static ICollection<T> Replace<T>(this ICollection<T> source, ICollection<T> newList) where T:IStateful

但是,现在该方法返回一个 IColllection,这迫使我将调用编写为:

myStatefulSetOfStuff = myStatefulSetOfStuff.Replace(GetNewSetOfStuff()).ToList();

如何重新编写我的方法,以便在我的通话中不需要.ToList()

编辑: 似乎有些混乱,所以我会尝试清除它。我有一个清单。我想使用新列表对该列表执行操作。没问题。我想出了如何使用扩展方法返回一个列表。

但我意识到,嘿,Replace() 中的实际代码并不特定于列表,它可以应用于任何集合。所以我修改了 Replace 以返回一个 ICollection。这会强制调用方法看起来像

var newStuff = left.Replace(right).ToList()

var newStuff = left.Replace(right).ToArray()

等等

但是我不想说 ToList、ToArray 等,我希望方法只是从源对象中推断出正确的返回类型。所以我可以说

var newStuff = left.Replace(right);

和 newStuff 将与 left 的类型相同。 Right 也属于同一类型。

【问题讨论】:

  • myStatefulSetOfStuff 是什么类型?
  • sourcenewList 必须是同一类型吗?或者只要两种类型都实现ICollection&lt;T&gt;,它们可以是单独的类型吗?
  • source 和 newList 将属于同一类型。

标签: c# generics extension-methods


【解决方案1】:

试试下面的

public static TCollection Replace<TCollection, TItem>(
  this TCollection source,   
  TCollection newList)
    where TCollection : ICollection<TItem>
    where TItem : IStateful

这是一个用例示例

interface IStateful { }
class Foo : IStateful { }
static void Test()
{
    ICollection<Foo> left = null, right= null;
    left.Replace<ICollection<Foo>, Foo>(right);
}

不幸的是,在这种情况下,泛型参数确实显得必要(无法让类型推断适用于这种特定情况)

编辑

我的回答是基于对问题的一点误读。我认为目的是将source 的类型流向方法的返回类型。在进一步重新阅读后,您似乎希望在所有情况下都流式传输任何源并返回List。在这种情况下,我建议您查看 Reed 的答案。

【讨论】:

  • +1:这将起作用,这就是所要求的,但它仅在输入是列表时才起作用 - 不确定这是否是 OP 真正想要做的。
  • @Reed 你能澄清一下吗?我只使用 ICollection&lt;T&gt; 类型。授予类型推断由于某种原因失败,但我可以通过明确指定类型来使其工作
  • @JaredPar:例如,您不能将 List&lt;T&gt; 用于返回类型和源,而将不同的 ICollection&lt;T&gt; 用于“newList”参数。不确定这是否是必需的,但听起来,从问题来看,他想要 ICollection 输入但 IList&lt;T&gt; 结果。
  • @Reed 我明白你现在的意思了。不得不重新阅读这个问题几次。
  • @JaredPar:是的 - 虽然不确定这里到底想要什么 - 我已经考虑过这个,但它仍然可能需要.ToList(),具体取决于输入类型,这是原始的一部分问题。
【解决方案2】:

如果您需要它始终返回 IList&lt;T&gt;,,只需将其更改为:

public static IList<T> Replace<T>(this ICollection<T> source, ICollection<T> newList) where T:IStateful

并将.ToList() 调用放在您的扩展方法中(除非它已经在内部创建了一个列表)。

话虽如此,如果您愿意,您可以通过使用两个类型参数来“嵌套”它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-02
    • 1970-01-01
    • 2022-06-15
    • 2015-03-22
    • 1970-01-01
    • 2015-01-11
    • 1970-01-01
    相关资源
    最近更新 更多