Получение выходного параметра string[] в виде IEnumerable<string>

Допустим, у нас есть метод:

public void SomeMethod(out string[] someArray) { // ... }

Есть ли способ сделать что-то похожее на это:

IEnumerable<string> result;

SomeMethod(out result);

Изменить: Дело в том, что я не хочу связывать выходное значение с string[]Я хотел бы, чтобы код работал, даже если объявление метода изменено на SomeMethod(out List<string> outputValue),

3 ответа

Решение

Нельзя изменять тип выходного параметра, потому что безопасность типов не может быть гарантирована. Это подробно объясняется в блоге Эрика Липперта.

Вот пример кода, как можно нарушить безопасность типов, если это будет разрешено:

IEnumerable<string> result;

public void Test()
{
   SomeMethod(out result);
}

public void SomeMethod(out string[] someArray)
{
   someArray = new string[];
   ChangeTheType();

   int n = someArray.Length;    // BANG!! - someArray is now a List<string>
}

public void ChangeTheType()
{
    result = new List<string>();
}

Очевидно, это проблема, только если результат не находится в той же области, что и вызов SomeMethod, но компилятор не будет проверять это. Это просто не разрешено.

Измените подпись метода на public void SomeMethod(out IEnumerable<string> someStrings), Вы можете назначить string[] в someStrings внутри SomeMethod и если позже вы решите использовать List<string> Вы можете назначить это также без торможения вызова.

Лично я бы исключил параметры в первую очередь: public string[] SomeMethod(),

Вы не можете сделать это, и нет никакого способа обойти это. Одна из причин, почему CLR не поддерживает out, только ref, Так out на самом деле представляется как ref, с некоторыми специальными правилами, добавленными компилятором C#.

Самый простой (и очевидный) способ - создать отдельную переменную:

string[] resultArray;

SomeMethod(out resultArray);
IEnumerable<string> result = resultArray;

Вы могли бы создать вспомогательный метод, чтобы сделать это для вас:

public delegate void ActionWithOut<T>(out T result);

public static void ConvertOut<TBase, TDerived>(
    ActionWithOut<TDerived> method, out TBase result)
    where TDerived : TBase
{
    TDerived derived;
    method(out derived);
    result = derived;
}

Использование:

IEnumerable<string> result;
ConvertOut<IEnumerable<string>, string[]>(SomeMethod, out result);

Но вам потребуется отдельная перегрузка (и тип делегата) для каждого количества параметров, и код на самом деле выглядит не намного лучше. (Параметры типа необходимы, вывод типа не работает для этого кода.)

Я уверен, что это не лучший способ, но вы можете написать другой метод, который сделает эту работу за вас:

public class ClassA
    {
        private void SomeMethod(out IEnumerable<string> result)
        {
            string[] res;
            SomeMethod(out res);
            result = res;
        }

        public void SomeMethod(out string[] someArray)
        {
            someArray = new string[2];
        }

        void Test()
        {
            IEnumerable<string> result;
            SomeMethod(out result);
        }
    }
Другие вопросы по тегам