Использование ключевого слова "params" для общих параметров в С#
Сегодня я встретил красивый Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, TResult>
делегат в С#.NET 4.5. Я предполагаю, что 16 было произвольным местом для остановки (какие методы имеют более 16 параметров?), Но это заставило меня задуматься: возможно ли в С# указать, что общий тип может иметь любое количество аргументов типа? аналогичным образом, что ключевое слово params для методов допускает любое количество аргументов для метода. Что-то вроде этого:
public class MyInfiniteGenericType<params T[]> { ... }
где внутри класса вы могли бы получить доступ к аргументам типа путем перечисления через них или с помощью T[index]
таким же образом, что params
допускает внутри методов.
У меня никогда не было пользы для этого лично, но делегат Func был бы идеальным местом для его использования. Не было бы необходимости в 16 различных типах Func!
Итак, мой вопрос: это можно сделать каким-либо образом в С#, а , если нет, это глупая идея?
Ответы
Ответ 1
возможно ли в С# указать, что общий тип может иметь любое количество аргументов типа?
Нет, у С# нет ничего подобного, я боюсь.
По существу Func<T>
и Func<T1, T2>
являются полностью несвязанными типами в отношении CLR, и нет ничего похожего на params
для указания нескольких аргументов типа.
Что касается его полезности: я могу видеть случаи, когда это может быть полезно, но я подозреваю, что они достаточно редки, чтобы означать, что функция не пересекает порог "выгоды/стоимость". (Обратите внимание, что это почти наверняка потребует изменений CLR тоже.)
Ответ 2
В С++ 11 есть функция, о которой вы, по сути, говорите. Они называют это variadic templates.
Генераторы С# не совсем похожи на С++-шаблоны, и это затруднит создание совершенно той же вещи.
В случае С++ шаблоны расширяются во время компиляции в зависимости от того, какие конкретные типы используются. В случае с С# спецификация типа происходит полностью во время выполнения. И получившийся IL должен поддерживать число встречающихся типов.
Ответ 3
Нет, невозможно получить произвольное количество общих аргументов. Вероятно, это и глупая идея, потому что параметры универсального типа не разрешены во время выполнения, они разрешены во время компиляции, и поэтому повторение таких действий не является очевидной задачей.
Вы также можете подумать, что Tuple <,,,, > может быть очевидным местом для него, но решение есть, когда вы исчерпали общие аргументы, вы делаете последнее из Tuple <, > для остальных полей.
Ответ 4
Нет, это невозможно сделать.
Это не так просто, как рассматривать его как массив типов (понятие, которое даже не существует в С#). Рассмотрим Func
- количество параметров типа должно быть таким же, как число параметров метода делегата Invoke
. Но как программист мог бы выразить такую связь между параметрами типа и регулярными параметрами?
Однако эта функция существует в С++ 11 - variadic templates. Обратите внимание, что С++ не позволяет получать доступ к параметрам отдельного типа с использованием синтаксиса массива - вместо этого функции обычно отделяют первый параметр типа от остальных и используют рекурсивные вызовы для распаковки остальных.
Ответ 5
Я просто обнаружил, что мне любопытно узнать, может ли кто-нибудь еще использовать это. Я написал общий композитор для создания композитов из миксинов, собранных с использованием функции Castle Dynamic Proxy.
Я построил композитор для поддержки двух микшинов и собирался продолжить "копирование и вставку и настройку (bleh)" двух композиторов mixin на еще 15 вариаций вплоть до 17 микширующего композитора (аналогично Func<T>
через Func<T1...T16, T>
). Но потом я подумал, не было бы здорово, если бы я мог просто определить Composer<TComposer, TIComposite, params[] TIMixin>
!
К сожалению, я готов копировать и вставлять и корректировать (сама деятельность, которую генерируют нам не общие).