C# generics: любой способ ссылаться на общие типы параметров как на коллекцию?

мне нужно написать кучу методов, которые принимают 1..N параметры универсального типа, например:

int Foo<T1>();
int Foo<T1,T2>();
int Foo<T1,T2,T3>();
...
int Foo<T1,T2,T3...TN>();

внутри Foo() Я хотел бы сделать что-то для каждого типа, например

int Foo<T1,T2,T3>() {
    this.data = new byte[3]; // allocate 1 array slot per type
}

есть ли способ параметризовать это, чтобы я не редактировал каждую вариацию Foo(), что-то аналогичное:

int Foo<T1,T2,T3>() {
    this.data = new byte[_NUMBER_OF_GENERIC_PARAMETERS];
}

В идеале, я также хотел бы иметь возможность получить массив или коллекцию типов:

int Foo<T1,T2,T3>() {
    this.data = new byte[_NUMBER_OF_GENERIC_PARAMETERS];

    // can do this
    Type [] types = new Type[] { T1, T2, T3 };
    // but would rather do this
    Type [] types = _ARRAY_OR_COLLECTION_OF_THE_GENERIC_PARAMETERS;
}

4 ответов


вы можете прочитать текущие общие параметры и их номер из MethodInfo.GetGenericArguments array.

вы можете получить MethodInfo для текущего метода, с помощью MethodBase.GetCurrentMethod метод.

обратите внимание, что вам все равно нужно будет предоставить несколько общих перегрузок вашего метода с различным количеством общих параметров, так как C# и CLI не поддерживают вариадические общие списки параметров.

Итак, ваш пример кода для метода с три общих параметра могут быть записаны следующим образом:

int Foo<T1,T2,T3>() {
    MethodInfo mInfo = (MethodInfo)MethodBase.GetCurrentMethod();
    Type[] types = mInfo.GetGenericArguments();

    this.data = new byte[types.Length];
}

1) Вы можете получить количество аргументов шаблона через отражение: http://msdn.microsoft.com/en-us/library/system.reflection.methodbase.getcurrentmethod.aspx . Таким образом, вы можете иметь общую реализацию для каждого ФОО. В каждом Foo вы можете просто позвонить:

FooImpl();

единственная разница (относительно "GetCurrentMethod") заключается в том, что вам нужно будет получить информацию о методе предыдущего метода:

StackTrace stackTrace = new StackTrace();
MethodBase methodBase = stackTrace.GetFrame(1).GetMethod();

2) Вы можете генерировать все версии Foo во время выполнения - все будут иметь одинаковую реализацию вызова только FooImpl. Некоторые сведения о генерации методов во время выполнения:создание функции динамически во время выполнения и вот:http://msdn.microsoft.com/en-us/library/exczf7b9.aspx


.NET framework рассматривает универсальный класс или метод с параметрами типа N как имеющий другое имя, чем тот, у которого больше или меньше. Вероятно, было бы возможно без огромного изменения структуры организовать вещи так, чтобы вызвать функцию

foo<T>(autogeneric ref T it)

as:

foo(1, "George", 5.7);

будет переведено как:

struct foo99 {public int p1; public string p2; public double p3};
...
foo99 temp99;
temp99.p1 = 1;
temp99.p2 = "George";
temp99.p3 = 5.7;
foo1(ref temp);

это позволит общему методу эффективно принимать произвольное количество параметров. Возможность пройти такой анонимный структура ref может показаться не очень полезной, но она может быть очень мощной в сочетании с лямбдами.

обычно для закрытия локальных переменных в лямбда-выражении требуется поднять локальные переменные в объект кучи и создать делегат, который нацелен на этот объект кучи. Если можно использовать вышеуказанный стиль, можно вместо создания постоянного объекта закрытия и делегата и передачи делегата просто поднять соответствующие переменные в структуру и передать byref к нему вместе со статическим делегатом. Это будет работать только в тех случаях, когда вызываемая процедура не будет настаивать на закрытии передачи, но с другой стороны, вызывающий будет знать, что вызываемая процедура не настаивайте на закрытии. Кроме того, хотя никакие языки .NET не будут поддерживать такую вещь, и некоторые изменения в рамках могут потребоваться, чтобы позволить коду, который сделал это, быть изменчивым, передавая по ссылке структуру, некоторые из членов которой также были byrefs, могут сделайте возможным для лямбды доступ к заключительной процедуре ref параметры--что-то, что в настоящее время невозможно (поскольку нет никакой гарантии, что созданный делегат не переживет область, где он был создан). Структуры умирают, когда умирает область, в которой они находятся, поэтому проблема не должна существовать с ними.

Я хотел бы, чтобы языки .NET имели удобный способ выражения этих понятий. Тот факт, что закрытие может привести к произвольному сохранению времени жизни переменных означает, что код, который когда-либо использовал переменную в закрытии, должен предполагать, что внешний код может изменить ее в любое время. Структурный подход не будет иметь этой проблемы.


нет. Вы не можете использовать параметр Type, как хотите. Но вы можете использовать что-то вроде кортежа!--2-->. Это позволяет обернуть дженерики. Но вы не можете использовать сам TypeParamter.