Visual Studio designer failures “type could not be read” errors

In one of our larger development projects, we began to notice the following designer error when opening forms with user controls embedded :

Type  could not be read from the data in line N position N.  The type’s internal structure may have changed.  Either implement ISerializable on the type or provide a type converter that can provide a more reliable conversion format, such as text or an array of bytes.  The conversion exception was: Unable to load type [CLR Type Information]

Our first point of confusion was the line N position N information.  The CLR Type referenced by the error did not exist in any code file at Line N.  How could the designer be failing to open a form by executing code which didn’t exist at the location the designer said it was failing at.

Our second point of confusion was that removing ALL references to the offending type still resulted in the designer error occurring when opening the form.

OK, time to brew a pot of coffee and put on our thinking caps….

<Coffee gone, solution found>

The cause
We tracked the cause (not the root problem… we’ll discuss that in a minute) to the user controls.  In several of the user controls, there exists get/set accessors which take an IList<T> collection using the following code pattern

 

public partial class ListManagerDisplayControl: UserControl
{

public ListManagerDisplayControl()
{
InitializeComponent();
}

private Guid _CustomerGUID;
public Guid CustomerGUID
{
set { _CustomerGUID = value; }
}

public IList<Type> DataList
{
set { _DataList = value;}
get{ return _DataList; }
}

 

The problem is the Get/Set accessor.  When you drop the usercontrol on a form, the designer attempts to populate all of the properties in the form.designer.cs which is pretty standard stuff… until you look at the DataList property…. in the designer, the IDE will produce lines of code similar to

 

//
// uiListManagerControl
//
this.uiListManagerControl.Location = new System.Drawing.Point(x,y);
this.uiListManagerControl.Size = new System.Drawing.Size(x,y);
this.uiListManagerControl.DataList = new List<Type>();

 

 

The problems turns out to be the uiListMangerControl.DataList = new List<Type>();

The Real Root Cause
OK, for those keeping score, the line uiListMangerControl.DataList = new List<Type>();  should not have any impacts on the designer and certainly would not result in the error we were seeing.  And you would be right.

Enter the resource file….

To support localization, control properties can be stored in the form.resx file.  In our case, the property was being populated by the following form.designer.cs line of code:

//
// uiListManagerControl
//
this.uiListManagerControl.Location = new System.Drawing.Point(x,y);
this.uiListManagerControl.Size = new System.Drawing.Size(x,y);
this.uiListManagerControl.DataList = ((System.Collections.Generic.IList<Type>)(resources.GetObject(“uiListManagerControl.DataList “)));

 

Hey, that looks like it serialized the IList<> object… interesting.  A quick peek at the resource file showed the following

<data name=”uiListManagerControl.DataList”
mimetype=”application/x-microsoft.net.object.binary.base64″>
<value>
LOTSOFBINARY64ENCODEDCHARACTERS
</value>
</data>

 

And behold, the line number of the binary data exactly matched the line number being reported in our error.

Solutions

Solution One
Remove the Get portion of the accessor.  If no data is returned by the user control DataList property, the IDE designer will not put anything into the designer file.  (Be sure to delete the offending entries from the designer file or the error will continue)

This solution worked well for us as the IList<> collection type is a reference type.  There is no need (in our scenario) to return another pointer to the same location in memory… the owning form already knows where the data is.  The user control (in this case) is merely a reusable display for common data

Solution Two
Use the [DesignerSerializationVisibility()] attribute to define how the property is serialized.

 

Additional Notes
In our case, the error was created by an IList<> type.  Based on our research, this error can (and probably will) occur for most complex types when exposed as properties on a user control.

 

OK, problem solved… time to shoot some Nazi Zombies…