我有以下两种通用类型:
interface IRange<T> where T : IComparable<T>
interface IRange<T, TData> : IRange<T> where T : IComparable<T>
^---------^
|
+- note: inherits from IRange<T>
现在我想为这些接口的集合定义一个扩展方法,因为它们都是或者是它们的IRange<T>
后代,IRange<T>
我希望我可以定义一个可以处理这两者的方法。请注意,该方法不需要处理两者之间的任何差异,只需处理来自IRange<T>
.
我的问题是这样的:
我可以定义一个扩展方法来处理IEnumerable<T>
这两种类型中的任何一种的集合()吗?
我试过这个:
public static void Slice<T>(this IEnumerable<IRange<T>> ranges)
where T : IComparable<T>
然而,传递一个IEnumerable<IRange<Int32, String>>
,像这样:
IEnumerable<IRange<Int32, String>> input = new IRange<Int32, String>[0];
input.Slice();
给了我这个编译器错误:
错误 1“System.Collections.Generic.IEnumerable>”不包含“Slice”的定义,并且找不到接受“System.Collections.Generic.IEnumerable>”类型的第一个参数的扩展方法“Slice”(你是缺少 using 指令或程序集引用?) C:\Dev\VS.NET\LVK\LVK.UnitTests\Core\Collections\RangeTests.cs 455 26 LVK.UnitTests
注意:我没想到它会编译。我对 co(ntra)-variance 有足够的了解(总有一天我需要知道哪个是哪个方式)知道那是行不通的。我的问题是我是否可以对 Slice 声明做任何事情以使其发挥作用。
好的,然后我尝试推断范围接口的类型,这样我就可以处理所有类型,IEnumerable<R>
只要有R
问题是IRange<T>
.
所以我尝试了这个:
public static Boolean Slice<R, T>(this IEnumerable<R> ranges)
where R : IRange<T>
where T : IComparable<T>
这给了我同样的问题。
那么,有没有办法调整这个?
如果没有,我唯一的选择是:
- 定义两个扩展方法,并在内部调用一个内部方法,可能是通过将其中一个集合转换为包含基本接口的集合?
- 等待 C# 4.0?
以下是我设想定义这两种方法的方式(注意,我仍处于早期设计阶段,所以这可能根本不起作用):
public static void Slice<T>(this IEnumerable<IRange<T>> ranges)
where T : IComparable<T>
{
InternalSlice<T, IRange<T>>(ranges);
}
public static void Slice<T, TData>(this IEnumerable<IRange<T, TData>> ranges)
where T : IComparable<T>
{
InternalSlice<T, IRange<T, TData>>(ranges);
}
private static void Slice<T, R>(this IEnumerable<R> ranges)
where R : IRange<T>
where T : IComparable<T>
这是一个显示我的问题的示例程序代码。
请注意,通过在 Main 方法中将调用从 Slice1 更改为 Slice2 会使两种用法都产生编译器错误,因此我的第二次尝试甚至没有处理我最初的情况。
using System;
using System.Collections.Generic;
namespace SO1936785
{
interface IRange<T> where T : IComparable<T> { }
interface IRange<T, TData> : IRange<T> where T : IComparable<T> { }
static class Extensions
{
public static void Slice1<T>(this IEnumerable<IRange<T>> ranges)
where T : IComparable<T>
{
}
public static void Slice2<R, T>(this IEnumerable<R> ranges)
where R : IRange<T>
where T : IComparable<T>
{
}
}
class Program
{
static void Main(string[] args)
{
IEnumerable<IRange<Int32>> a = new IRange<Int32>[0];
a.Slice1();
IEnumerable<IRange<Int32, String>> b = new IRange<Int32, String>[0];
b.Slice1(); // doesn't compile, and Slice2 doesn't handle either
}
}
}