简体   繁体   English

T是可枚举的通用接口上的扩展方法<K>

[英]Extension methods on a generic interface where T is Enumerable<K>

I'm implementing a fluent argument assertion library where the focus is in strong type checking on compile time. 我正在实现一个流畅的参数声明库,该库的重点是在编译时进行强类型检查。 Intellisense should only show methods and extensions available for the asserted type. Intellisense应该仅显示可用于断言类型的方法和扩展。

I'm having problems resolving proper type arguments when creating an extension for IEnumerable. 为IEnumerable创建扩展时,我在解析正确的类型参数时遇到问题。

Idea in the library is that you can call ThrowIf (or ThrowIfNot) on any type which will return you an assertion instance of type IAssertion: 库中的想法是,您可以在任何类型上调用ThrowIf(或ThrowIfNot),这将返回IAssertion类型的断言实例:

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

Now I want to check against IEnumerable if it contains a specific item. 现在,我要检查IEnumerable是否包含特定项目。 There will be two overloads where one takes the object of type T as a parameter and the other takes a function where to do the evaluation: 将有两个重载,一个重载类型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;
}

Everything goes fine when using the overload taking an instance of the actual type. 使用重载并使用实际类型的实例时,一切都很好。 But the latter one with the function compiler cannot infer the type arguments properly unless cast is made: 但是使用函数编译器的后一种除非进行强制转换,否则无法正确推断类型参数:

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

Is there any way I could make the compiler happy without doing the cast for the function parameter? 有什么方法可以使编译器满意而无需对function参数进行强制转换?

More implementation details can be found from here: https://bitbucket.org/mikalkai/argument-assertions/overview 可以从这里找到更多的实现细节: https : //bitbucket.org/mikalkai/argument-assertions/overview

Disclaimer: This answer is only valid if IAssertion can be made covariant . 免责声明:仅当可以将IAssertion设为协变时,此答案才有效。

Assuming that IAssertion is covariant, you don't necessarily need two generic type parameters T1 and T2 for the Contains methods. 假设IAssertion是协变的,对于Contains方法,您不一定需要两个通用类型参数T1T2 Instead, you specify IEnumerable in your interface directly and use only one generic type parameter like this: 相反,您直接在界面中指定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;
}

Then you can use the contains method like this: 然后可以使用如下的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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM