gpt4 book ai didi

c# - C# 3 中具有接口(interface)继承(co(ntra)-variance?)的泛型类型推断

转载 作者:行者123 更新时间:2023-11-30 12:18:35 26 4
gpt4 key购买 nike

我有以下两种通用类型:

interface IRange<T> where T : IComparable<T>
interface IRange<T, TData> : IRange<T> where T : IComparable<T>
^---------^
|
+- note: inherits from IRange<T>

现在我想为这些接口(interface)的集合定义一个扩展方法,因为它们都是 IRange<T>或来自 IRange<T>我希望我可以定义一种方法来处理这两种情况。请注意,该方法不需要处理两者之间的任何差异,只需处理来自 IRange<T> 的公共(public)部分。 .

因此我的问题是:

我可以定义一个扩展方法来处理这两种类型之一的集合 ( 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();

给我这个编译器错误:

Error 1 'System.Collections.Generic.IEnumerable>' does not contain a definition for 'Slice' and no extension method 'Slice' accepting a first argument of type 'System.Collections.Generic.IEnumerable>' could be found (are you missing a using directive or an assembly reference?) C:\Dev\VS.NET\LVK\LVK.UnitTests\Core\Collections\RangeTests.cs 455 26 LVK.UnitTests

注意:我没想到它能编译。我对 co(ntra)-方差(总有一天我需要了解哪一种是哪种方式)了解得足够多,知道那是行不通的。我的问题是我是否可以对 Slice 声明做任何事情来使其工作。

好的,然后我尝试推断范围接口(interface)的类型,以便我可以处理所有类型的 IEnumerable<R>只要R有问题的是 IRange<T> .

所以我尝试了这个:

public static Boolean Slice<R, T>(this IEnumerable<R> ranges)
where R : IRange<T>
where T : IComparable<T>

这给了我同样的问题。

那么,有什么方法可以调整它吗?

如果没有,我唯一的选择是:

  1. 定义两个扩展方法,并在内部调用一个内部方法,可能是通过将集合之一转换为包含基本接口(interface)的集合?
  2. 等待 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
}
}
}

最佳答案

我认为您正确回答了自己的问题 - 如果没有 C# 4.0 对接口(interface)的协变/逆变支持,您将被迫编写一些重复代码。

您可能还想使用 IEnumerable<T> Enumerable.Cast<T>(this IEnumerable collection)方法 - 它是延迟执行的,因此您可以在代码中(明确地)使用它在 T 和 T 的子类之间进行转换,而无需创建新集合。

尽管如此,您可能想要编写自己的强制转换,因为没有任何约束可确保集合包含 T 的后代,因此您对运行时异常持开放态度。我想具有以下语法的函数可以工作,但您将失去混合类型推断和扩展方法的能力:

public static IEnumerable<T> Cast<T,TSubset>(IEnumerable<TSubset> source)
where TSubset : T
{
foreach(T item in source) yield return item;
}

不幸的是,你必须指定 T,所以漂亮干净的扩展语法消失了(如果有一些约定允许你在扩展方法上进行类型推断,并且仍然允许显式声明类型参数,那就太好了,无需重复可以推断出的类型。

关于c# - C# 3 中具有接口(interface)继承(co(ntra)-variance?)的泛型类型推断,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1936785/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com