Wil*_*alf 6 .net c# generics extension-methods compiler-errors
作为一个爱好项目(并让我更深入地沉浸在泛型/扩展方法中),我正在编写一个参数检查库!
我有一个名为Argument的模型,它描述了一个参数,如下所示:
public class Argument<T>
{
internal Argument(string name, T value)
{
Name = name;
Value = value;
}
public string Name { get; private set; }
public T Value { get; private set; }
}
Run Code Online (Sandbox Code Playgroud)
当参数验证开始时,将创建此对象的实例,并通过调用挂起它的扩展方法(包含实际逻辑)来执行各个验证.
一种这样的扩展方法验证集合是否包含至少一个项目,并且当前看起来像这样:
public static Argument<IEnumerable<T>> HasItems<T>(this Argument<IEnumerable<T>> argument)
{
if (!argument.Value.Any())
throw Error.Generic(argument.Name, "Collection contains no items.");
return argument;
}
Run Code Online (Sandbox Code Playgroud)
但它似乎不起作用.如果我是,比如写这个单元测试:
[TestMethod]
public void TestMethod1()
{
var argument = new List<int>() { 1, 2, 6, 3, -1, 5, 0 };
Validate.Argument("argument", argument)
.IsNotNull()
.HasItems()
.All(v => v.IsGreaterThan(0));
}
Run Code Online (Sandbox Code Playgroud)
HasItems不显示在IntelliSense起来,和我得到这个编译错误:
'Validation.Argument<System.Collections.Generic.List<int>>'不包含'HasItems'的定义,也没有扩展方法'HasItems'接受类型的第一个参数'Validation.Argument<System.Collections.Generic.List<int>>'(你是否缺少using指令或汇编引用?)
如果我尝试将值直接传递给扩展方法,如下所示:
CollectionTypeExtensions.HasItems(Validate.Argument("argument", argument));
Run Code Online (Sandbox Code Playgroud)
我明白了:
最好的重载方法匹配
'Validation.CollectionTypeExtensions.HasItems<int>(Validation.Argument<System.Collections.Generic.IEnumerable<int>>)'有一些无效的参数
基于我的研究,我需要这个工作称为"方差",并且适用于接口和委托,但不适用于类(即:所有类都是不变的.)
也就是说,它可能会以另一种方式运作.想到的是重写它直接转到T,就像这样:
public static Argument<T> HasItems<T, TElement>(this Argument<T> argument)
where T : IEnumerable<TElement>
{
if (!argument.Value.Any())
throw Error.Generic(argument.Name, "Collection contains no items.");
return argument;
}
Run Code Online (Sandbox Code Playgroud)
..但是这不起作用,因为它需要在调用方法时显式指定TElement.我也可以回退到在类型约束中使用非通用的IEnumerable接口,但是我必须找到一种方法将IEnumerable强制转换为IEnumerable(这需要知道该上下文中的T是什么),或者重复Any()的功能是为了测试任何项目的存在,并且还有另一种扩展方法(All),它会非常非常混乱,所以我宁愿避免使用它.
所以最终,我想我的问题是:如何让我的扩展方法正确附加?
这对你有用吗?看起来有点笨拙,但确实有效。
public static Argument<T> HasItems<T>(this Argument<T> argument) where T: IEnumerable
{
if (!argument.Value.Cast<object>().Any())
{
throw Error.Generic(argument.Name, "Collection contains no items.");
}
return argument;
}
Run Code Online (Sandbox Code Playgroud)