【问题标题】:Extension methods on a generic interface where T is Enumerable<K>T 为 Enumerable<K> 的通用接口上的扩展方法
【发布时间】:2016-07-17 12:50:35
【问题描述】:

我正在实现一个流畅的参数断言库,其中的重点是编译时的强类型检查。 Intellisense 应该只显示可用于断言类型的方法和扩展。

在为 IEnumerable 创建扩展时,我在解析正确的类型参数时遇到问题。

库中的想法是,您可以在任何类型上调用 ThrowIf(或 ThrowIfNot),这将返回 IAssertion 类型的断言实例:

public static IAssertion<T> ThrowIf<T>(this T t)
{
    return new IfAssertion<T>(t);
}

现在我想检查 IEnumerable 是否包含特定项目。将有两个重载,一个将 T 类型的对象作为参数,另一个将一个函数用于执行评估:

public static T1 Contains<T1, T2>(this IAssertion<T1> assertion, T2 item)
    where T1 : IEnumerable<T2>
{
    // assertion logic
    return assertion.Value;
}

public static T1 Contains<T1, T2>(this IAssertion<T1> assertion, Func<T2, bool> func)
    where T1 : IEnumerable<T2>
{
    // assertion logic
    return assertion.Value;
}

使用重载获取实际类型的实例时一切正常。但是后一种使用函数编译器无法正确推断类型参数,除非进行强制转换:

var list = new List<string>();
list.ThrowIf().Contains("foo"); // compiles
list.ThrowIf().Contains((string s) => false); // compiles
list.ThrowIf().Contains(s => false); // does not compile

有没有什么方法可以让编译器满意而无需对函数参数进行强制转换?

更多实现细节可以从这里找到: https://bitbucket.org/mikalkai/argument-assertions/overview

【问题讨论】:

  • 我觉得你只能做Contains&lt;string&gt;(s =&gt; false)
  • 不。您需要将其命名为 Contains, string>(s => false)。

标签: c# interface extension-methods func inferred-type


【解决方案1】:

免责声明:此答案仅在IAssertion 可以设为covariant 时有效。

假设IAssertion 是协变的,则Contains 方法不一定需要两个泛型类型参数T1T2。相反,您可以直接在界面中指定IEnumerable,并且只使用一个泛型类型参数,如下所示:

public static IEnumerable<T> Contains<T>(this IAssertion<IEnumerable<T>> assertion, T item)
{
  // assertion logic
  return assertion.Value;
}

public static IEnumerable<T> Contains<T>(this IAssertion<IEnumerable<T>> assertion, Func<T, bool> func)
{
  // assertion logic
  return assertion.Value;
}

然后你可以像这样使用 contains 方法:

var list = new List<string>();
list.ThrowIf().Contains("foo"); // compiles
list.ThrowIf().Contains((string s) => false); // compiles
list.ThrowIf().Contains(s => false); // compiles now too

【讨论】:

  • IAssertion 可以并且是协变的。我实际上尝试直接在 IEnumerable 中绑定扩展,但由于某种原因,intellisense 说它找不到该方法。好吧,我只是在另一台机器和 tzadam 上尝试过,一切正常!这不是智能感知第一次搞砸了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多