【问题标题】:sometimes generic type infer not work. why this happen?有时泛型类型推断不起作用。为什么会这样?
【发布时间】:2018-02-02 09:16:14
【问题描述】:

我在我的 C# 中使用自定义扩展方法:

//version 1
public static IEnumerable<TSource> ForEachAndReturnSelf<TSource>(this IEnumerable<TSource> container, System.Action<TSource> delegateAction)
{ 
    foreach (var v in container) delegateAction(v); return container; 
} 

正如你可能猜到的,这个方法是一个稍微调整过的版本:

System.Collections.Generic.List<T>.ForEach()

唯一不同的是我的方法返回自身(不是 void):

无论如何,该版本的方法运行良好。
但是我有这个方法的新版本,它返回原始类型而不是IEnumerable&lt;TSource&gt;
于是我把方法改成了这样:

//version 2
public static T ForEachAndReturnSelf<T,TSource>(this T container, System.Action<TSource> delegateAction) where T : IEnumerable<TSource>
{ 
    foreach (var v in container) delegateAction(v); return container; 
} 

因为我需要这样使用它:

//Example Usage1
List<int> list = /* initialize */;
list.ForEachAndReturnSelf(_ => _ *= 2).Convert(_ => _.ToString()).Sort();

//Example Usage2
list.ForEachAndReturnSelf(_ => _ *= 2)[0] = 4;

但是当我将版本 1 更改为 2 时,使用此方法的所有代码部分现在都会产生编译器错误:

方法的类型参数 ExtentionMethods.ForEachAndReturnSelf<T,TSource>(this T, System.Action<TSource>) 无法从用法中推断出来。尝试 明确指定类型参数

问题是:
我认为提供的类型信息足以推断类型,但为什么不能呢?
以及如何满足提供类型知识,以便返回与提供的原始类型相同的类型?

【问题讨论】:

  • 什么是T?它是在哪里定义的?

标签: c# .net generics type-inference


【解决方案1】:

所以首先你的方法签名只有 1 个通用参数,它需要两个,所以它应该是这样的

public static TCollection ForEachAndReturn<TCollection, TItem>(this TCollection Container, Action<TItem> action)
        where TCollection : IEnumerable<TItem>
{
        foreach (var item in Container)
        {
            action(item);
        }

        return Container;
}

现在您仍然会收到您提到的编译器警告。这是因为它可以推断您的收藏类型。但是,您是通用约束,说TCollection 必须是IEnumerable&lt;TSource&gt; 类型,仅适用于提供有关TCollection 的信息。这就是为什么你需要告诉编译器TSource 的类型。通用约束就是这样,它们用于约束,您无法从您正在约束的事物中推断约束的类型,我想这可能会导致问题。因此,为什么不能从TCollection 提供的通用参数中推断出TSource

我希望这是有道理的。

编辑:有点抱歉,所以要摆脱编译器警告,你只需要提供类型信息。

var myList = new List<string>();

list.ForEachAndReturn<List<string>,string>(i => //do stuff);

【讨论】:

  • 首先,感谢您编辑我的代码和糟糕的英语。您对版本 2 的代码更正与我的意思完全相同。我理解你的解释。所以我认为剩下的唯一方法是实现每个容器版本而不是 IEnumerable。 (如 ForEachAndReturnSelf for List、for []、for Dictionary... 重载)
  • 我很抱歉我没有真正回答你问题的最后一部分。我将编辑我的答案,并希望能解释您如何做到这一点。
  • 感谢您最后的回答。这似乎是解决这个问题的完美答案。但是这种调整方法的目标就像语法糖一样。 (使用这种方法而不是 foreach ......所以它可以减少代码行和输入重复信息。)。使用了我整个项目的许多部分,并将继续下去。所以提供类型信息的显式方式不能作为语法糖。
【解决方案2】:

所以,首先,您只声明了一个通用参数,而您需要其中的 2 个。将方法的定义更改为:

public static TCollection ForEachAndReturnSelf<TCollection, TItem>(this TCollection container, System.Action<TItem> delegateAction) where TCollection : IEnumerable<TItem>

现在要使用它,您必须包含用于调用此方法的泛型类型,如下所示:

meList.ForEachAndReturnSelf<List<int>, int>(i => ... );

Try this online

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-15
    • 2023-03-05
    • 1970-01-01
    • 2016-09-16
    • 1970-01-01
    • 2015-08-11
    相关资源
    最近更新 更多