Передача списка int в качестве параметра пользовательскому веб-элементу управления

Я хочу передать список int (List) в качестве декларативного свойства пользовательскому веб-элементу управления следующим образом:

<UC:MyControl runat = "server" ModuleIds = "1,2,3" />

Для этого я создал TypeConverter:

public class IntListConverter : System.ComponentModel.TypeConverter
{
    public override bool CanConvertFrom(
           System.ComponentModel.ITypeDescriptorContext context, 
           Type sourceType)
    {
        if (sourceType == typeof(string)) return true;
        return base.CanConvertFrom(context, sourceType);
    }
    public override object ConvertFrom(
      System.ComponentModel.ITypeDescriptorContext context, 
      System.Globalization.CultureInfo culture, object value)
    {
        if (value is string)
        {
            string[] v = ((string)value).Split(
                new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            List<int> list = new List<int>();
            foreach (string s in vals)
            {
                list.Add(Convert.ToInt32(s));
            }
            return list
        }
        return base.ConvertFrom(context, culture, value);
    }
    public override bool CanConvertTo(ITypeDescriptorContext context,
      Type destinationType)
    {
        if (destinationType == typeof(InstanceDescriptor)) return true;
        return base.CanConvertTo(context, destinationType);
    }
    public override object ConvertTo(ITypeDescriptorContext context,
      System.Globalization.CultureInfo culture, object value, Type destinationType)
    {
        if (destinationType == typeof(InstanceDescriptor) && value is List<int>)
        {
            List<int> list = (List<int>)value;
            ConstructorInfo construcor = typeof(List<int>).GetConstructor(new Type[] { typeof(IEnumerable<int>) });
            InstanceDescriptor id = new InstanceDescriptor(construcor, new object[] { list.ToArray() });
            return id;
        }
        return base.ConvertTo(context, culture, value, destinationType);
    }
}

А затем добавил атрибут к моему свойству:

[TypeConverter(typeof(IntListConverter))]
public List<int> ModuleIds
{
    get { ... }; set { ... };
}

Но я получаю эту ошибку во время выполнения:

Unable to generate code for a value of type 'System.Collections.Generic.List'1[[System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]'. This error occurred while trying to generate the property value for ModuleIds.

Мой вопрос аналогичен найденному здесь, но решение не решает мою проблему:

Обновлять: Я нашел страницу, которая решила первую проблему. Я обновил приведенный выше код, чтобы показать свои исправления. Добавленный код - это методы CanConvertTo и ConvertTo. Теперь у меня другая ошибка:

Object reference not set to an instance of an object.

Эта ошибка, по-видимому, косвенно вызвана чем-то в методе ConvertTo.

Конечно, вы не написали IntListConverter в имени класса и IntegerListConverter в атрибуте, не так ли?

Alan 30.10.2008 22:36

Ха, нет ... Я исправлю это.

Kevin Albrecht 30.10.2008 22:54

Спасибо, что задали этот вопрос. Я столкнулся с почти такой же проблемой.

Ashraf Sabry 18.12.2013 17:59
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
12
3
4 859
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

передать список из кода позади ...

aspx:

<UC:MyControl id = "uc" runat = "server" />

код программной части:

List<int> list = new List<int>();
list.add(1);
list.add(2);
list.add(3);

uc.ModuleIds = list;

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

Kevin Albrecht 30.10.2008 23:36

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

Rismo 31.10.2008 11:54

Проблема в том, что для этого требуются изменения в коде, что нарушает разделение декларативной и недекларативной частей кода.

Kevin Albrecht 31.10.2008 19:52

Обычно я делаю это так, чтобы свойство обертывало коллекцию ViewState. Ваш способ выглядит лучше, если его можно заставить работать, но это выполнит свою работу:

public IList<int> ModuleIds
{
   get
   {
       string moduleIds = Convert.ToString(ViewState["ModuleIds"])

       IList<int> list = new Collection<int>();

       foreach(string moduleId in moduleIds.split(","))
       {
          list.Add(Convert.ToInt32(moduleId));
       }

      return list;
   }
}

Идея интересная, но все же не оптимальная, так как не позволяет декларативной разметке работать.

Kevin Albrecht 30.10.2008 23:54

Я считаю, что проблема в наборе {}. Преобразователь типов хочет преобразовать List<int> обратно в строку, но CanConvertFrom() не работает для List<int>.

Нет, этот случай обрабатывается методом ConvertTo, который для ясности не показан.

Kevin Albrecht 30.10.2008 23:53

Вы можете передать его в строку и разделить запятыми, чтобы заполнить частную переменную. Не имеет тонкости атрибуции, но будет работать.

private List<int> modules;
public string ModuleIds
{
  set{
    if (!string.IsNullOrEmpty(value))
    {
    if (modules == null) modules = new List<int>();
    var ids = value.Split(new []{','});
    if (ids.Length>0)
      foreach (var id in ids)
        modules.Add((int.Parse(id)));
    }
}

Это возможно, но не решает проблемы. То, что я пытаюсь сделать, должно быть возможным, не так ли?

Kevin Albrecht 31.10.2008 19:50

Хотя я не могу сказать, что у меня есть особый опыт работы с этой ошибкой, другие источники указывают, что вам необходимо добавить преобразование в тип InstanceDescriptor. проверить:

http://weblogs.asp.net/bleroy/archive/2005/04/28/405013.aspx

Что дает объяснение причин или альтернативно:

http://forums.asp.net/p/1191839/2052438.aspx#2052438

Который предоставляет пример кода, похожего на ваш.

Кажется, это правильное направление, но я все равно получаю сообщение об ошибке. Смотрите мое обновление.

Kevin Albrecht 31.10.2008 00:57

Я думаю, что лучший вариант - сделать так, чтобы ваш пользовательский элемент управления имел свойство в стиле DataSource.

Вы берете свойство как объект, а затем выполняете некоторую проверку типов по IList / IEnumerable / etc, чтобы убедиться, что оно правильное.

Ответ принят как подходящий

После подключения отладчика к Cassini я вижу, что нулевой ref на самом деле исходит от System.Web.Compilation.CodeDomUtility.GenerateExpressionForValue, который в основном пытается получить выражение для массива int [], который вы передаете в конструктор List. Поскольку для массива int [] нет дескриптора типа, он терпит неудачу (и выдает в процессе пустую ссылку вместо «не может сгенерировать исключение набора свойств», которое должно).

Я не могу понять встроенный способ получения сериализуемого значения в List <int>, поэтому я просто использовал статический метод:

class IntListConverter : TypeConverter {
    public static List<int> FromString(string value) {
       return new List<int>(
          value
           .Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
           .Select(s => Convert.ToInt32(s))
       );
    }

    public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) {
        if (destinationType == typeof(InstanceDescriptor)) {
            List<int> list = (List<int>)value;
            return new InstanceDescriptor(this.GetType().GetMethod("FromString"),
                new object[] { string.Join(",", list.Select(i => i.ToString()).ToArray()) }
            );
        }
        return base.ConvertTo(context, culture, value, destinationType);
    }
}

+1 И за этот ответ. Рабочее исправление очень малоизвестной проблемы. У меня была та же проблема, что и у OP, за исключением использования List<string> вместо List<int>. Решение отлично сработало с несколькими незначительными изменениями для учета строки и int.

KP. 24.05.2011 19:51

Спасибо за этот ответ. Теперь я понимаю: построитель страниц может генерировать выражение «1,2,3», но не может генерировать новое выражение List <string> {«1», «2», «3»}. Есть ли способ указать строителю выдавать такое выражение?

Ashraf Sabry 18.12.2013 18:06

Мне не понравилась идея записать значение в виде строки типа «1,2,3» в сгенерированном файле класса управления, потому что оно будет десериализоваться при каждом запросе, поэтому я написал ControlBuilder для своего выражения, чтобы затем инициализировать коллекцию добавляет каждое значение, вызывая метод Add

Ashraf Sabry 19.12.2013 15:17

Я решил нечто похожее, создав 2 свойства:

public List<int> ModuleIDs { get .... set ... }
public string ModuleIDstring { get ... set ... }

ModuleIDstring преобразует свой набор значений в список и устанавливает свойство ModuleIDs.

Это также позволит использовать ModuleID из PropertyGrid и т. д.

Хорошо, не лучшее, безопасное решение, но для меня оно работает.

Вероятно, это решение, которое мы в конечном итоге выберем, но все еще странно, что мы не можем понять, как исправить настоящую ошибку.

Kevin Albrecht 31.10.2008 19:54

Другие вопросы по теме