Преобразовать строку в зависимости от ее признака в БД в простые типы данных C#
Вытаскиваю с БД таблицу в которой есть |id|Code|Type|Value| в модель:
public record MyDto
{
public Guid Id{ get; set; }
public Code Code { get; set; }
public Type Type { get; set; }
public string Value { get; set; }
}
Необходимо по признаку |Type| вернуть из метода соответствующий тип данных лежащий в поле Value которая парситься всегда в строку, но ее содержимое может быть например "100" или "Привет Мир!". Я ничего лучшего пока не придумал, но очень сомнительный код:
public async Task<object> GetDataByCodeAsync(Code code, CancellationToken token)
{
var result = await _repository.GetDataByCodeAsync(code, token);
switch (result.Type)
{
case Type.String:
return result.Value.ToString();
case Type.Decimal:
return Convert.ToDecimal(result.Value);
case Type.Integer:
return Convert.ToInt32(result.Value);
case Type.Guid:
return Guid.Parse(result.Value);
default:
throw new ArgumentOutOfRangeException();
}
}
Можно пока без проверок или TryParse, просто сугубо понимать, как реализовать в нормальном виде.
Ответы (1 шт):
Можно применить паттерн-матчинг для лаконичности:
return result.Type switch
{
SettingType.String => result.Value,
SettingType.Decimal => decimal.Parse(result.Value),
SettingType.Integer => int.Parse(result.Value),
SettingType.Guid => Guid.Parse(result.Value),
_ => throw new ArgumentOutOfRangeException()
};
Давайте разберёмся.
Ваш метод GetDataByCodeAsync возвращает какое-то значение. Что дальше с ним происходит? Очевидно, оно как-то обрабатывается. И, вероятно, обрабатывать нужно по разному в зависимости от типа.
Мне много раз попадались такие вопросы с конвертацией типа из строки и дальнейшим его использованием. На предложения показать проблему более широко практически всегда авторы упираются и хотят непременно чёрную магию: чтобы оно само как-то работало...
В тех задачах, что я видел, обычно код выглядит примерно так:
object value = GetDataByCode(...);
Process(value);
Внутри Process опять приходится определять, какой именно тип имеет параметр value: if (value is int n) ... и т. п. То есть от чего уходили, к тому и вернулись. Разница лишь в том, что теперь тип задан не строкой.
Предлагаю следующее.
public async Task ProcessDataByCodeAsync(Code code, CancellationToken token = default)
{
var result = await _repository.GetDataByCodeAsync(code, token);
switch (result.Type)
{
case SettingType.String:
Process(result.Value);
break;
case SettingType.Decimal:
Process(decimal.Parse(result.Value));
break;
case SettingType.Integer:
Process(int.Parse(result.Value));
break;
case SettingType.Guid:
Process(Guid.Parse(result.Value));
break;
default:
throw new ArgumentOutOfRangeException();
}
}
И несколько перегрузок метода, принимающих нужный тип:
void Process(string value) { }
void Process(decimal value) { }
void Process(int value) { }
void Process(Guid value) { }
Таким образом наш метод выполняет диспетчеризацию в одном-единственном месте. А дальше мы без проблем работаем с конкретными типами.