69

我今天在 C# .NET 4.5 中遇到了漂亮的Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, TResult>委托。我假设 16 是一个任意的停止位置(哪些方法有超过 16 个参数?)但它让我思考:在 C# 中是否可以指定泛型类型可以有任意数量的类型参数?类似于方法的 params 关键字允许方法使用任意数量的参数。像这样的东西:

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

在类内部,您可以通过枚举类型参数或以与方法内允许T[index]的相同方式使用来访问类型参数。params

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

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

4

7 回答 7

58

是否可以在 C# 中指定泛型类型可以具有任意数量的类型参数?

不,我担心 C# 没有类似的东西。

从根本上说Func<T>Func<T1, T2>就 CLR 而言,它们是完全不相关的类型,没有什么params比指定多个类型参数更好的了。

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

于 2013-03-14T18:22:18.277 回答
13

C++11 具有您本质上正在谈论的功能。他们称之为可变参数模板

但是,C# 泛型与 C++ 模板不太一样,并且会使得构建完全相同的东西变得困难。

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

于 2013-03-14T18:25:09.627 回答
1

不,这是做不到的。

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

但是,此功能确实存在于 C++11可变参数模板中。请注意,C++ 不允许使用数组语法访问单个类型参数 - 相反,函数通常将第一个类型参数与其余类型参数分开,并使用递归调用来解包其余部分。

于 2013-03-14T18:26:08.940 回答
1

我只是发现自己很好奇,看看是否有其他人对此有用。我刚刚编写了一个通用作曲家,用于从使用 Castle Dynamic Proxy 组装的 mixin 构建复合材料。

我构建了 Composer 以支持两个 mixin,并且即将继续“复制、粘贴和调整 (bleh)”这两个 mixin composer 到 15 个变体,最多 17 个混合 composer(类似于Func<T>through Func<T1...T16, T>)。但后来我想,如果我能定义,那不是很好Composer<TComposer, TIComposite, params TIMixin[]>吗!

可悲的是,我要去复制、粘贴和调整(泛型帮助我们避免的活动)。

于 2015-05-14T22:09:57.843 回答
1

我有类似的问题。我需要params KeyValuePair<Base, Implementation>[] pairs,其中Implementation是从Base继承的。

最初,我想过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>()
);
于 2021-07-29T10:03:13.117 回答
0

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

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

于 2013-03-14T18:22:37.837 回答
0

我不知道这是否有用,但解决方法可能是:

Func<List<object>>

您必须手动将每个元素转换为相应的数据类型。您可以迭代地使用它:

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

你可以拥有你想要的一组变量。

于 2021-10-07T10:06:18.630 回答