简体   繁体   中英

Cannot create an object of type 'System.Object' from its string representation

Me and the webforms parser are having some difficulties today, regarding control properties I hope some of you can help me with!

I have a Control with a property named Value with object as type. When every time I declare it in my aspx I get the error

Cannot create an object of type 'System.Object' from its string representation '...' for the 'Value' property.

Wtf, isnt everything Objects? :)

I then tried to add a TypeConverter on my property, but no luck.

My Control

[ParseChildren(true, "Value")]
[TypeConverter(typeof(ExpandableObjectConverter))]
[ControlBuilder(typeof(ParamControlBuilder))]
public class Param : Control
{
    public string Name { get; set; }

    [TypeConverter(typeof(StringToObjectConverter))]
    public object Value { get; set; }

    protected override void AddParsedSubObject(object obj)
    {
        base.AddParsedSubObject(obj);
    }

    public override void DataBind()
    {
        base.DataBind();
    }

    protected override void DataBindChildren()
    {
        base.DataBindChildren();
    }
}

The TypeConverter

public class StringToObjectConverter : TypeConverter 
{
    public override bool IsValid(ITypeDescriptorContext context, object value)
    {
        return true;
    }

    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        if (sourceType == typeof(string))
        {
            return true;
        }

        return base.CanConvertFrom(context, sourceType);
    }

    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
    {
        if (destinationType == typeof(object))
        {
            return true;
        }

        if (destinationType == typeof(InstanceDescriptor))
        {
            return true;
        }

        return base.CanConvertTo(context, destinationType);
    }

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
    {
        return value.ToString();
    }

    public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
    {
        if (destinationType == typeof(object))
        {
            return (object)value;
        }

        if (destinationType == typeof(InstanceDescriptor))
        {
            return new InstanceDescriptor(typeof(object).GetConstructor(new Type[] { }), new object[] { });
        }

        return base.ConvertTo(context, culture, value, destinationType);
    }
}

What i want to do is to be able to write in my aspx page the following

<my:param name="A object" value="<# value_of_a_method()" %> runat="server" />
<my:param name="A object" value="this_is_just_a_string" runat="server" />

The first example works fine, the second fails with mentioned error. And no, i can't believe that the only way around this is to databind everytime, even for constant strings like

<my:param name="A object" value='<%# "this_is_just_a_string" %>' runat="server" />

What about adding a ValueAsString property that is actually the one serialized and prevent Value from being serialized?

ValueAsString would then be responsible for serializing and deserializing Value appropriately (such as XML or JSON serialization).

Update It turns out that, due to the way that ASP.Net builds the controls, there isn't a way to do what you are looking to do.

It is possible to implement a mechanism to get object types, such as strings or internal classes, to be processed, but if you include primitive types such as Ints in the mix, the framework won't even execute the TypeConverter for your Object Value.

For example, in the following two cases (using VB syntax), both Params will be created, but the Value for Param1 will be nothing:

<cti:Param ID="Param1" Value="<%# CInt(1) %>" runat="server" />
<cti:Param ID="Param2" Value="test" runat="server" />

For completeness, here is how I was able to implement an object converter without having ASP.Net throw a fit after realizing that it always needs an actual class to instantiate as opposed to just an Object:

First, create an intermediate class that the underlying logic can instantiate. This class will have one constructor for each object type class that can be implemented:

public class MyObjectConverter
{
    public MyObjectConverter() : base()
    {
    }
    public MyObjectConverter(string oValue) : this()
    {
        this.Value = oValue;
    }

    public object Value { get; set; }

    public override string ToString()
    {
        if (this.Value == null)
        {
            return string.Empty;
        }
        else
        {
            return this.Value.ToString();
        }
    }
}

Next, modify the StringToObjectConverter's ConvertTo method so that it creates an instance of the new class using the appropriate constructor (an object constructor still confuses the code here):

public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
    if (destinationType == typeof(object))
    {
        return (object)value;
    }

    if (destinationType == typeof(InstanceDescriptor))
    {
        return new InstanceDescriptor(typeof(MyObjectConverter).GetConstructor(new Type[] {value.GetType()}), new object[] {value});
    }

    return base.ConvertTo(context, culture, value, destinationType);
}

Finally, in the Param object, modify the Value property to handle the new type:

private object m_Value;
[TypeConverter(typeof(StringToObjectConverter))]
public object Value
{
    get
    {
        return m_Value;
    }
    set
    {
        if (value is MyObjectConverter)
        {
            m_Value = ((MyObjectConverter)value).Value;
        }
        else
        {
            m_Value = value;
        }
    }
}

I suppose it might be possible to generate dynamic classes or constructors or the object converter class, but that is not something that I have experience with, so I can't really speak to whether or not that is a viable solution.

So, to summarize, there are two issues with this approach:

1) You cannot use it for primitive data types. However, even using an Object Value property without bringing strings into the equation does not support this functionality.

2) You must explicitly define constructors for all of the data types that you wish to support.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM