Хорошо, давайте предположим, что мы отказались от другого вопроса, в котором вы ошибочно полагаете, что все это является ошибкой компилятора, и на самом деле решаете ваш реальный вопрос.
Прежде всего, давайте попробуем сформулировать реальный вопрос.Вот мой пример:
Преамбула:
Метод "variadic" - это метод, который принимает неопределенное количество параметров заранее.
Стандартный способ реализации переменных методов в C #:
void M(T1 t1, T2 t2, params P[] p)
, то есть ноль или более обязательных параметров, за которыми следует массив, помеченный как «params».
При вызове такого метода метод применим либо в его нормальной форме (без параметров), либо в расширенной форме (с параметрами).То есть вызов
void M(params object[] x){}
формы
M(1, 2, 3)
генерируется как
M(new object[] { 1, 2, 3 });
, поскольку он применим только в расширенной форме.Но вызов
M(new object[] { 4, 5, 6 });
генерируется как
M(new object[] { 4, 5, 6 });
, а не
M(new object[] { new object[] { 4, 5, 6 } });
, потому что он применим в своей обычной форме.
C # поддерживает небезопасную ковариацию массивов для массивов элементов ссылочного типа.То есть string[]
может быть неявно преобразовано в object[]
, даже если попытка изменить первый элемент такого массива на нестроковый вызовет ошибку времени выполнения.
Вопрос:
Я хочу позвонить в форме:
M(new string[] { "hello" });
и иметь этот акт, как метод был применим только в расширенной форме:
M(new object[] { new string[] { "hello" }});
, а не нормальной формы:
M((object[])(new string[] { "hello" }));
Есть ли способ в C # реализовать методы с переменным числом аргументов, которые не становятся жертвами комбинациинебезопасная ковариация массива и применяемые методы преимущественно в их обычной форме?
Ответ
Да, есть способ, но он вам не понравится. Лучше сделать метод невариантным, если вы намереваетесь передавать ему отдельные массивы.
Реализация Microsoft на C # поддерживает недокументированное расширение , которое позволяетдля методов с вариациями в стиле C, которые не используют массивы params. Этот механизм не предназначен для общего использования и включен только для команды CLR и других авторов, создающих библиотеки взаимодействия, чтобы они могли писать код взаимодействия, который соединяет C # и языки, которые ожидают вариационные методы в стиле C. Я настоятельнорекомендуем против попыток сделать это самостоятельно.
Механизм для этого включает использование недокументированного ключевого слова __arglist
.Базовый эскиз:
public static void M(__arglist)
{
var argumentIterator = new ArgIterator(__arglist);
object argument = TypedReference.ToObject(argumentIterator.GetNextArg());
Вы можете использовать методы итератора аргумента, чтобы пройтись по структуре аргумента и получить все аргументы.И вы можете использовать супермагический типизированный эталонный объект для получения типов аргументов. Можно даже использовать эту технику для передачи ссылок на переменные в качестве аргументов, но, опять же, я не рекомендую делать это.
Что особенно ужасно в этой технике, так это то, что вызывающая сторона должназатем скажите:
M(__arglist(new string[] { "hello" }));
, что откровенно выглядит довольно брутто в C #.Теперь вы понимаете, почему вам лучше просто полностью отказаться от вариационных методов;просто сделайте так, чтобы вызывающий передавал массив и покончил с этим.
Опять же, мой совет: (1) ни при каких обстоятельствах не пытайтесь использовать эти недокументированные расширения языка C #, которые предназначены для удобства CLRавторы команды внедрения и библиотеки взаимодействий, и (2) вы должны просто отказаться от методов с переменным числом мест;они не подходят для вашей проблемной области.Не боритесь против инструмента;выберите другой инструмент.