【问题标题】:Passing int list as a parameter to a web user control将 int 列表作为参数传递给 Web 用户控件
【发布时间】:2010-09-20 01:39:07
【问题描述】:

我想将一个 int 列表 (List) 作为声明性属性传递给 Web 用户控件,如下所示:

<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.

我的问题与找到的here 类似,但解决方案没有解决我的问题:

更新:我找到了解决第一个问题的页面。我更新了上面的代码以显示我的修复。添加的代码是CanConvertTo 和ConvertTo 方法。现在我得到一个不同的错误。:

Object reference not set to an instance of an object.

这个错误似乎是由ConvertTo 方法中的某些东西间接引起的。

【问题讨论】:

  • 你肯定没有在类名中写IntListConverter,在属性中写IntegerListConverter吧?
  • 哈,不...我会解决的。
  • 感谢您提出这个问题。我遇到了几乎同样的问题。

标签: c# asp.net typeconverter


【解决方案1】:

在将调试器挂钩到 Cassini 后,我看到 null ref 实际上来自 System.Web.Compilation.CodeDomUtility.GenerateExpressionForValue,它基本上是在尝试获取传递给 List 构造函数的 int[] 数组的表达式.由于 int[] 数组没有类型描述符,因此它会失败(并在进程中抛出 null ref,而不是应该的“无法生成属性集异常”)。

我无法找到将可序列化值放入 List 的内置方法,所以我只使用了静态方法:

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 对于这个答案也是如此。对一个非常晦涩的问题的有效修复。除了使用List&lt;string&gt; 而不是List&lt;int&gt; 之外,我遇到了与OP 相同的问题。解决方案通过一些小的更改完美地解决了字符串与 int 的问题。
  • 感谢您的回答。现在我明白了:页面构建器能够发出 "1,2,3" 表达式,但不能发出新的 List{"1","2","3"} 表达式。有没有办法指示构建器发出这样的表达式?
  • 我不喜欢在生成的控件类文件中将值写为“1,2,3”之类的字符串的想法,因为它会在每次请求时被反序列化,所以我写了一个 ControlBuilder让我的表达式初始化集合,然后通过调用 Add 方法添加每个值
【解决方案2】:

虽然我不能说我对此错误有任何特殊经验,但其他来源表明您需要将转换添加到 InstanceDescriptor 类型。退房:

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

提供原因的解释或替代:

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

它提供了与您类似的示例代码。

【讨论】:

  • 这似乎是正确的方向,但我仍然收到错误消息。查看我的更新。
【解决方案3】:

我通过创建 2 个属性解决了一些类似问题:

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

ModuleIDstring 将其值集转换为列表并设置 ModuleIDs 属性。

这也将使 ModuleID 可以从 PropertyGrid 等中使用。

好吧,这不是最好的类型安全解决方案,但对我来说它有效。

【讨论】:

  • 这可能是我们最终会采用的解决方案,但我们无法弄清楚如何修复实际错误仍然很奇怪。
【解决方案4】:

从后面的代码中传递列表...

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;

【讨论】:

  • 这是我一直在使用的解决方法,但绝对不是最佳的。
  • 对我来说,这看起来比类型转换器类好得多。哪个更具可读性?
  • 这样做的问题是它需要修改后面的代码,这打破了代码的声明性和非声明性部分的分离。
【解决方案5】:

我通常这样做的方式是让属性包装 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;
   }
}

【讨论】:

  • 有趣的想法,但仍然不是最佳的,因为它不允许声明性标记工作。
【解决方案6】:

我认为问题出在集合{}。类型转换器想要将List&lt;int&gt; 改回字符串,但CanConvertFrom() 对List&lt;int&gt; 失败。

【讨论】:

  • 不,这种情况由 ConvertTo 方法处理,为清楚起见,未显示。
【解决方案7】:

您可以将其传递到字符串中并以逗号分隔以填充私有变量。没有精确的归因,但会起作用。

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)));
    }
}

【讨论】:

  • 这是可能的,但不能解决问题。我想做的事情应该是可能的,不是吗?
【解决方案8】:

我认为您最好的选择是让您的用户控件具有 DataSource 样式的属性。

您将属性作为一个对象,然后对 IList/IEnumerable/ 等进行一些类型检查以确保它是正确的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-15
    • 2011-02-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多