Переменная, разделенная запятыми, в общий список
Мне удалось преобразовать строку, разделенную запятыми, в IList<int>
, но как я могу изменить ее, чтобы получить IList<T>
, где T будет передан как один из входных параметров?
i.e, если мне нужно IList<int>
, я передам "int" в качестве параметра, если мне нужно IList<string>
, я передам "string" в качестве параметра.
Моя идея - получить тип, будь то int или string через входной параметр, и использовать отражение и преобразовать строку в соответствующий список
Код для преобразования строки, разделенной запятой, как IList<int>
public static IList<int> SplitStringUsing(this string source, string seperator =",")
{
return source.Split(Convert.ToChar(seperator))
.Select(x => x.Trim())
.Where(x => !string.IsNullOrWhiteSpace(x))
.Select(int.Parse).ToList();
}
Примечание: Выше код еще не протестирован
Я ищу что-то вроде
public static IList<T> SplitStringUsing(this string source, string seperator =",", T t)
{
find the type of t and convert it to respective List
}
Ответы
Ответ 1
Вы можете использовать Convert.ChangeType(объект, строка) для синтаксического анализа базовых типов, поддерживаемых System.Convert или любой другой класс, который реализует IConvertible interface
public static IList<T> SplitStringUsing<T>(string source, string seperator = ",")
where T:IConvertible
{
return source.Split(Convert.ToChar(seperator))
.Where(x => !string.IsNullOrWhiteSpace(x))
.Select(x=>Convert.ChangeType(x,typeof(T)))
.Cast<T>()
.ToList();
}
Чтобы избежать проблем с локализацией, вы должны, вероятно, добавить параметр IFormatProvider, чтобы позволить вызывающему указать культуру для использования или по умолчанию для текущей культуры, например:
public static IList<T> SplitStringUsing<T>(string source,
string seperator = ",",
IFormatProvider provider =null)
where T:IConvertible
{
return source.Split(Convert.ToChar(seperator))
.Where(x => !string.IsNullOrWhiteSpace(x))
.Select(x=>Convert.ChangeType(x,typeof(T),provider))
.Cast<T>().ToList();
}
Для более общего случая вы можете передать код разбора в виде лямбда для функции:
public static IList<T> SplitStringUsing<T>(string source,
Func<string,T> parser,
string seperator = ",")
{
return source.Split(Convert.ToChar(seperator))
.Where(x => !string.IsNullOrWhiteSpace(x))
.Select(parser)
.ToList();
}
и назовите его следующим образом:
var l1 = SplitStringUsing(x,s=>double.Parse(s,NumberStyles.HexNumber,
CultureInfo.InvariantCulture));
У вас могут быть оба метода в коде, и компилятор выберет правильную перегрузку.
Ответ 2
Мне кажется, вам нужно Convert.ChangeType, вот так. Он не полностью протестирован, компилируется и исправляется.
public static IList<T> SplitStringUsing(string source, string seperator =",")
{
return source.Split(Convert.ToChar(seperator))
.Select(x => x.Trim())
.Where(x => !string.IsNullOrWhiteSpace(x))
.Select((T)Convert.ChangeType( x, typeof( T ) )).ToList();
}
Ответ 3
Я хотел бы продлить ответ @PanagiotisKanavos.
В частности, общий подход:
public static class StringToListExtension
{
//see https://msdn.microsoft.com/en-us/library/System.String.Split.aspx
//and https://msdn.microsoft.com/en-us/library/bb548891.aspx
//this is the generic approach offering enough possibilies to use
public static IEnumerable<TResult> MapStringValues<TResult>(this String source, Func<String, TResult> itemMapper, String[] separator, StringSplitOptions options)
{
if (null == source) throw new ArgumentNullException("source");
return source.Split(separator, options).Select(itemMapper);
}
//add your implementation using MapStringValues<T>
public static IList<Int32> MapToInt32ListUsingParse(this String source, String[] separator, StringSplitOptions options)
{
return MapStringValues<Int32>(source, Int32.Parse, separator, options).ToList();
}
//or more convenient
public static IList<Int32> DefaultMapToIntList(this String source)
{
return MapStringValues<Int32>(source, Int32.Parse, DefaultSeparator, StringSplitOptions.RemoveEmptyEntries).ToList();
}
private static readonly String[] DefaultSeparator = new []{ "," };
}
Вы бы использовали этот код:
String values = "some,text,with,commas";
List<String> l1 = values.MapStringValues<String>(s => s, new []{ "," }, StringSplitOptions.None).ToList();
values = "2,4,,5,6";
IList<Int32> l2 = values.MapToInt32ListUsingParse(new []{ "," }, StringSplitOptions.RemoveEmptyEntries);
values = "2,4,,5,6";
IList<Int32> l3 = values.DefaultMapToIntList();
Вы можете добавить варианты удобства для всех случаев с String to T. Если вы не хотите, чтобы исключения были выбраны, просто выполните функцию синтаксического анализа, используя Int32.TryParse и т.д.