Вы можете использовать конвертер типов, чтобы привязать строку через запятую к последовательности значений. Однако преобразователь типов должен преобразовывать строку в последовательность напрямую. Это означает, что преобразователь типа должен быть настроен на что-то вроде IEnumerable<T>
или T[]
. Чтобы упростить ситуацию, я продолжу свое объяснение для IEnumerable<int>
, но если вы хотите вместо этого использовать массивы, вам следует просто убедиться, что преобразователь типов преобразуется в массив вместо того, что реализует IEnumerable<T>
.
Вы можете настроить преобразователь типа для IEnumerable<int>
, используя TypeDescriptor.AddAttributes
:
TypeDescriptor.AddAttributes(
typeof(IEnumerable<int>),
new TypeConverterAttribute(typeof(EnumerableIntTypeConverter)));
Это настраивает EnumerableIntTypeConverter
как преобразователь типа, который может преобразовывать IEnumerable<int>
.
Этот вызов должен быть сделан при запуске процесса, а в случае с ASP.NET Core это удобно сделать методом Startup.Configure
.
Вот EnumerableIntTypeConverter
, который преобразует разделенную запятыми строку чисел в список целых чисел:
internal class EnumerableIntTypeConverter : TypeConverter
{
private const char Separator = ',';
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
=> sourceType == typeof(string);
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (!(value is string @string))
throw new NotSupportedException($"{GetType().Name} cannot convert from {(value != null ? value.GetType().FullName : "(null)")}.");
if (@string.Length == 0)
return Enumerable.Empty<int>();
var numbers = new List<int>();
var start = 0;
var end = GetEnd(@string, start);
while (true)
{
if (!int.TryParse(
@string.AsSpan(start, end - start),
NumberStyles.AllowLeadingSign,
culture,
out var number))
throw new FormatException($"{GetType().Name} cannot parse string with invalid format.");
numbers.Add(number);
if (end == @string.Length)
break;
start = end + 1;
end = GetEnd(@string, start);
}
return numbers;
}
private static int GetEnd(string @string, int start)
{
var end = @string.IndexOf(Separator, start);
return end >= 0 ? end : @string.Length;
}
}
При анализе используется System.Memory
, чтобы избежать выделения новой строки для каждого числа в списке. Если ваша структура не имеет перегрузки int.TryParse
, которая принимает Span<char>
, вы можете использовать string.Substring
.