在 C # 中对泛型参数使用“ params”关键字

我在 C # 中遇到了美丽的 Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, TResult>代表。NET 4.5.我假设16是一个任意的停止位置(什么方法有超过16个参数?)但是它让我想到: 有没有可能在 C # 中指定一个泛型类型可以有任意数量的类型参数?以类似的方式,params 关键字 for 方法允许一个方法的任意数量的参数。就像这样:

public class MyInfiniteGenericType<params T[]> { ... }

然后在类中通过枚举类型参数或使用 T[index]访问类型参数,方法与 params允许在方法中使用的方法相同。

我个人从来没有使用过这个,但是 Func 委托将是使用它的一个完美地方。将不需要16种不同类型的 Func!

所以我的问题是,这能在 C # 和 如果不是,这是一个愚蠢的想法中以任何方式实现吗?

21711 次浏览

有没有可能在 C # 中指定一个泛型类型可以有任意数量的类型参数?

不,恐怕 C # 没有这样的东西。

基本上,就 CLR 而言,Func<T>Func<T1, T2>是完全不相关的类型,没有什么类似于 params来指定多个类型参数。

至于它的实用性: 我可以看到它可能有用的情况,但我怀疑它们足够罕见,意味着该功能不会跨越“收益/成本”门槛。(请注意,这几乎肯定也需要更改 CLR。)

不,不可能有任意数量的泛型参数。这可能也是一个愚蠢的想法,因为泛型类型参数不会在运行时解析,而是在编译时解析,所以像这样迭代它们根本不是一件明显的事情。

您可能还认为 Tuple < ,,,,,,> 可能是一个显而易见的位置,但是解决方案是,当您用完了通用参数时,为其余字段将最后一个参数设置为 Tuple < ,,,,,> 。

C + + 11有一个特性,他们称之为 可变模板

不过,C # 泛型与 C + + 模板不太一样,因此很难构建完全相同的东西。

在 C + + 的例子中,模板在编译时被扩展为所使用的具体类型。在 C # 情况下,类型规范完全发生在运行时。产生的 IL 需要支持遇到的不同类型的数量。

不,这不可能。

这并不像把它当作一个类型数组那么简单(这个概念甚至在 C # 中都不存在)。考虑 Func-类型参数的数量必须与委托的 Invoke方法的参数数量相同。但是程序员如何表达类型参数和常规参数之间的这种关系呢?

但是,这个特性在 C + + 11-可变模板中确实存在。请注意,C + + 不允许使用数组语法访问单个类型参数——相反,函数通常将第一个类型参数与其他类型参数分开,并使用递归调用来解压剩下的类型参数。

我只是很好奇是否还有其他人需要这个。我刚编写了一个通用作曲家,用城堡动态代理(Castle Dynamic Proxy)组装的 Mixin 构建复合材料。

我构建了一个支持两个混音的作曲家,并准备在 “复制、粘贴和调整(见鬼)”上继续将两个混音作曲家分成15个更多的变体,最多17个混音作曲家(类似于 Func<T>Func<T1...T16, T>)。但是后来我想,如果我能定义 Composer<TComposer, TIComposite, params TIMixin[]>,那该多好啊!

遗憾的是,我要开始复制、粘贴和调整了(这正是泛型帮助我们避免的活动)。

我也有过类似的问题。 我需要 params KeyValuePair<Base, Implementation>[] pairs,其中 实施是遗传的 基地

最初,我考虑的是 IDictionary<Type, Type>,但这会扼杀泛型在这里的使用。

所以,我创建了一个接口:

public interface IMapping
{
Type Key { get; }
Type Value { get; }
}

以及它的实施:

public class Mapping<Base, Implementation> : IMapping where Base : class where Implementation : class, Base
{
public Type Key => typeof(Base);
public Type Value => typeof(Implementation);


}

创建了一个方法:

public static void Initialize(params IMapping[] mappings)
{
foreach (var mapping in mappings)
{
//We got our mapping, let's map
}
}

然后把它用作:

Initialize(
new Mapping<IMainView, MainView>(),
new Mapping<IDashboardView, DashboardView>()
);

我不知道这是否有用,但一个变通办法可能是:

Func<List<object>>

您必须手动将每个元素转换为相应的数据类型:

 Convert.ChangeType(obj, obj.GetType())//using System;

你可以得到你想要的变量集。