Как наиболее правильней и корректней вернуть более одного значения в методе? С#

208
02 декабря 2021, 17:40

Мне надо чтоб метод вернул четыре значения один bool, один string и два float. Я делаю это с помощью Dictionary<bool, string> Но Dictionary мне кажется создан для списков и этот вариант я думаю не совсем правильный. Как обычное вы делаете, когда функция должна вернуть более одного значения? Как это сделать правильней и эффективней?

Answer 1

Рассмотрим вариант номер 1 - простейший массив

public object[] GetPerson1()
{
    return new object[] { "Vasya", 120, new DateTime(1980, 1, 1) };
}

Все вроде ок, но вот пробема. Если кто то вызывает вашу функцию, ему надо догадываться, что это за значения вы передаете. То есть без вашего кода, например, не понять, что такое 120.

Второй вариант уже лучше

public Dictionary<string, object> GetPerson2()
{
    return new Dictionary<string, object> { { "name", "Vasya" }, { "height", 120 }, { "birthday", new DateTime(1980, 1, 1) }};
}

Но тут, чтобы пользователю функции понять назначения переменных, не достаточно просто вызвать функцию - придется проитерировать словарь или снова идти читать ваш код.

Следующий вариант ещё немного лучше

public (string name, int height, DateTime birthDate) GetPerson3()
{
    return ("Vasya", 120, new DateTime(1980, 1,1));
}

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

var person3 = GetPerson3(); 
person3.height = -100;

Потому, если вы хотите делать вещи правльно, но сначала определим класс человека

public sealed class Person
{
    public string Name { get; }
    public int Height { get; }
    public DateTime BirthDate { get; }
    public Person(string name, int height, DateTime birthDate)
    {
        if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException(nameof(name));
        if (height <= 0) throw new ArgumentException(nameof(height));
        if (birthDate.Year < 1900) throw new ArgumentException(nameof(birthDate));
        Name = name;
        Height = height;
        BirthDate = birthDate;      
    }
}

Вы видите тут 3 вещи:

  1. Входящих параметров три. Нельзя создать экземпляр такого класса, но с 2 параметрами или 4. Только 3.
  2. Каждый параметр валидируется, то есть нельзя создать экземпляр с неверными значениями параметров.
  3. Класс только на чтение. После создания экземпляра уже нельзя его поменять.

Ну и как бонус, программисту, который будет вызывать ваш метод, нет смысла смотреть на код вашего метода, какой бы он ни был. В принципе, он даже на код класса Person может не глядеть - все поля ему подскажет Intellisense. Поменять созданный класс он тоже не сможет, что уменьшет количество ошибок в разы, хотя и увеличивает кодичество кода.

READ ALSO
Микрофризы при ожидание коннекта по tcp в IEnumerator-е

Микрофризы при ожидание коннекта по tcp в IEnumerator-е

Ожидаю подключение к tcp данным кодом:

197
WP - вывод 7 постов от актуальной даты

WP - вывод 7 постов от актуальной даты

У меня есть рубрика, в которой много постовПосты начинаются, к примеру, с "21 декабря 2019 года"

88
Аналог CRON на PHP

Аналог CRON на PHP

Да, google был просмотрелВозможно плохо, но всё таки: есть файлик sync

147
Передача файлов на удаленный сервер

Передача файлов на удаленный сервер

Нужен совет по обработке сравнительно большого количества данных

110